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

First PM version that can do custom attributes

parent baa18516
#pragma once #pragma once
#include <iostream> #include <iostream>
#include <memory>
#include <typeindex> #include <typeindex>
#include "../Mesh.hh"
#include "../attributes.hh" #include "../attributes.hh"
namespace polymesh namespace polymesh
...@@ -15,43 +17,42 @@ public: ...@@ -15,43 +17,42 @@ public:
virtual ~GenericAttributeSerializer() {} virtual ~GenericAttributeSerializer() {}
/// can this attribute be (de)serialized by this serializer? /// can this attribute be (de)serialized by this serializer?
virtual bool isCompatibleTo(primitive_attribute_base<vertex_tag> const &attr) = 0; virtual bool is_compatible_to(primitive_attribute_base<vertex_tag> const &attr) = 0;
virtual bool isCompatibleTo(primitive_attribute_base<halfedge_tag> const &attr) = 0; virtual bool is_compatible_to(primitive_attribute_base<halfedge_tag> const &attr) = 0;
virtual bool isCompatibleTo(primitive_attribute_base<edge_tag> const &attr) = 0; virtual bool is_compatible_to(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<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<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<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<edge_tag> const &attr) = 0;
virtual void serialize(std::ostream &out, primitive_attribute_base<face_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; // pointer to tag as dummy parameter to allow deserialize to be used in templates over the tag type
virtual void deserialize(std::istream &in, primitive_attribute_base<halfedge_tag> &attr) = 0; 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, primitive_attribute_base<edge_tag> &attr) = 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, primitive_attribute_base<face_tag> &attr) = 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;
virtual std::type_index vertexAttributeType() = 0;
}; };
template <typename T, typename SerDes> template <typename T, typename serdes>
class AttributeSerializer : GenericAttributeSerializer class AttributeSerializer final : public GenericAttributeSerializer
{ {
public: 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); 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); 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); 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); return dynamic_cast<primitive_attribute<face_tag, T> const *>(&attr);
} }
...@@ -62,19 +63,52 @@ public: ...@@ -62,19 +63,52 @@ public:
mSerdes.serialize(out, specific.data(), specific.size()); 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); auto const &specific = dynamic_cast<primitive_attribute<face_tag, T> const &>(attr);
mSerdes.deserialize(in, specific.data(), specific.size()); mSerdes.serialize(out, specific.data(), specific.size());
} }
std::type_index vertexAttributeType() override { void deserialize(std::istream &in, Mesh const &mesh, attribute_collection &attrs, std::string const &name, vertex_tag *) override
return typeid (primitive_attribute<vertex_tag, T>); {
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: private:
SerDes mSerdes; serdes mSerdes;
}; };
} }
} }
#include "pm.hh" #include "pm.hh"
#include <iostream>
#include <fstream> #include <fstream>
#include <iostream>
#include <mutex> #include <mutex>
#include <typeindex> #include <typeindex>
#include <unordered_map> #include <unordered_map>
...@@ -8,28 +8,35 @@ ...@@ -8,28 +8,35 @@
namespace polymesh namespace polymesh
{ {
static std::unordered_map<std::string, std::unique_ptr<detail::GenericAttributeSerializer>> sSerializersByName; static std::unordered_map<std::string, std::unique_ptr<detail::GenericAttributeSerializer>> sSerializers;
static std::unordered_map<std::type_index, detail::GenericAttributeSerializer *> sSerializersByTypeIndex;
static std::mutex sSerializersMutex; 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); for (auto const &pair : sSerializers)
sSerializersByTypeIndex[ptr->vertexAttributeType()] = ptr.get(); {
sSerializersByName[identifier] = std::move(ptr); if (pair.second->is_compatible_to(attr))
return {pair.first, pair.second.get()};
}
return {{}, nullptr};
} }
struct PMHeader struct PMHeader
{ {
char pm[4] = {'P', 'M', 0, 0}; char pm[4] = {'P', 'M', 0, 0};
uint32_t num_vertices; int32_t num_vertices;
uint32_t num_halfedges; int32_t num_halfedges;
uint32_t num_faces; int32_t num_faces;
uint32_t num_vertex_attributes; int32_t num_vertex_attributes;
uint32_t num_halfedge_attributes; int32_t num_halfedge_attributes;
uint32_t num_edge_attributes; int32_t num_edge_attributes;
uint32_t num_face_attributes; int32_t num_face_attributes;
bool valid() const { return pm[0] == 'P' && pm[1] == 'M' && pm[2] == 0 && pm[3] == 0; } bool valid() const { return pm[0] == 'P' && pm[1] == 'M' && pm[2] == 0 && pm[3] == 0; }
}; };
...@@ -38,15 +45,65 @@ template <class Tag> ...@@ -38,15 +45,65 @@ template <class Tag>
static std::istream &read_index(std::istream &in, primitive_index<Tag> &idx) static std::istream &read_index(std::istream &in, primitive_index<Tag> &idx)
{ {
int32_t val; int32_t val;
in.read(reinterpret_cast<char*>(&val), sizeof(int32_t)); in.read(reinterpret_cast<char *>(&val), sizeof(int32_t));
idx.value = val; idx.value = val;
return in; return in;
} }
template <class Tag> 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; 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) 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 ...@@ -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_vertices = mesh.all_vertices().size();
header.num_halfedges = mesh.all_halfedges().size(); header.num_halfedges = mesh.all_halfedges().size();
header.num_faces = mesh.all_faces().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)); out.write(reinterpret_cast<char *>(&header), sizeof(header));
for (int i = 0; i < header.num_halfedges; ++i) // Store mesh topology
write_index(out, ll.face_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)));
for (int i = 0; i < header.num_halfedges; ++i) for (int i = 0; i < header.num_halfedges; ++i)
write_index(out, ll.to_vertex_of(halfedge_index(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) for (int i = 0; i < header.num_halfedges; ++i)
write_index(out, ll.next_halfedge_of(halfedge_index(i))); write_index(out, ll.next_halfedge_of(halfedge_index(i)));
for (int i = 0; i < header.num_halfedges; ++i) for (int i = 0; i < header.num_halfedges; ++i)
write_index(out, ll.prev_halfedge_of(halfedge_index(i))); write_index(out, ll.prev_halfedge_of(halfedge_index(i)));
for (int i = 0; i < header.num_faces; ++i) // Store attributes
write_index(out, ll.halfedge_of(face_index(i))); storeAttributes(out, attributes.vertex_attributes());
storeAttributes(out, attributes.halfedge_attributes());
for (int i = 0; i < header.num_vertices; i++) storeAttributes(out, attributes.edge_attributes());
write_index(out, ll.outgoing_halfedge_of(vertex_index(i))); storeAttributes(out, attributes.face_attributes());
} }
bool read_pm(std::istream &input, Mesh &mesh, attribute_collection &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) ...@@ -91,23 +155,25 @@ bool read_pm(std::istream &input, Mesh &mesh, attribute_collection &attributes)
auto ll = low_level_api(mesh); auto ll = low_level_api(mesh);
ll.alloc_primitives(header.num_vertices, header.num_faces, header.num_halfedges); ll.alloc_primitives(header.num_vertices, header.num_faces, header.num_halfedges);
for (int i = 0; i < header.num_halfedges; ++i) for (int i = 0; i < header.num_faces; ++i)
read_index(input, ll.face_of(halfedge_index(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) for (int i = 0; i < header.num_halfedges; ++i)
read_index(input, ll.to_vertex_of(halfedge_index(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) for (int i = 0; i < header.num_halfedges; ++i)
read_index(input, ll.next_halfedge_of(halfedge_index(i))); read_index(input, ll.next_halfedge_of(halfedge_index(i)));
for (int i = 0; i < header.num_halfedges; ++i) for (int i = 0; i < header.num_halfedges; ++i)
read_index(input, ll.prev_halfedge_of(halfedge_index(i))); read_index(input, ll.prev_halfedge_of(halfedge_index(i)));
for (int i = 0; i < header.num_faces; ++i) // Store attributes
read_index(input, ll.halfedge_of(face_index(i))); restoreAttributes<vertex_tag>(input, mesh, attributes, header.num_vertex_attributes)
&& restoreAttributes<halfedge_tag>(input, mesh, attributes, header.num_halfedge_attributes)
for (int i = 0; i < header.num_vertices; i++) && restoreAttributes<edge_tag>(input, mesh, attributes, header.num_edge_attributes)
read_index(input, ll.outgoing_halfedge_of(vertex_index(i))); && restoreAttributes<face_tag>(input, mesh, attributes, header.num_face_attributes);
return !input.fail(); return !input.fail();
} }
...@@ -123,5 +189,4 @@ bool read_pm(const std::string &filename, Mesh &mesh, attribute_collection &attr ...@@ -123,5 +189,4 @@ bool read_pm(const std::string &filename, Mesh &mesh, attribute_collection &attr
std::ifstream in(filename, std::ios::binary); std::ifstream in(filename, std::ios::binary);
return read_pm(in, mesh, attributes); return read_pm(in, mesh, attributes);
} }
} }
...@@ -24,17 +24,31 @@ namespace detail ...@@ -24,17 +24,31 @@ namespace detail
template <typename T> template <typename T>
struct bytewise_serdes 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 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) { in.read(static_cast<char *>(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> template <typename T, typename serdes = detail::bytewise_serdes<T>>
void registerType(std::string const &identifier, SerDes &&serializer = 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); auto ptr = std::make_unique<detail::AttributeSerializer<T, serdes>>(serializer);
detail::registerAttributeSerializer(identifier, std::move(ptr)); 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