It would be nice to make some SFML classes like sf::Vector, sf::Rect, sf::Color, sf::Vertex, sf::VertexArray, ..., serializable.
It's sometimes paintfull to send complex entities throught the network or to save them into a file. (Especially when entities have a lot of objects and vectors)
template <typename Archive>
void serialize(Archive & ar, const unsigned int version) {
ar & position.x;
ar & position.y;
ar & position.z;
ar & color.r;
ar & color.g;
ar & color.b;
ar & color.a;
ar & texCoords.x;
ar & texCoords.y;
}
Ok this code is good but I have to change everything because SFML classes are not serializable so :
class ODFAEG_GRAPHICS_API Material {
friend class boost::serialization::access;
private :
struct TextureInfo {
private :
const Texture* texture;
sf::IntRect rect;
std::string texId;
public :
TextureInfo (const Texture* texture, sf::IntRect rect, std::string texId="") {
this->texture = texture;
this->rect = rect;
this->texId = texId;
}
void setTexId(std::string texId) {
this->texId = texId;
}
std::string getTexId() {
return texId;
}
bool operator== (TextureInfo& info) {
return texture == info.texture;
}
bool operator!= (TextureInfo& info) {
return texture != info.texture;
}
const Texture* getTexture() const {
return texture;
}
sf::IntRect getTexRect() {
return rect;
}
template <typename Archive>
void serialize(Archive & ar, const unsigned int version) {
ar & texInfos;
ar & color.r;
ar & color.g;
ar & color.b;
ar & color.a;
}
};
std::vector<TextureInfo*> texInfos;
sf::Color color;
public :
int getNbTextures () {
return texInfos.size();
}
void addTexture (const Texture* texture, sf::IntRect rect) {
texInfos.push_back(new TextureInfo(texture, rect));
}
sf::IntRect getTexRect(int texUnit = 0) {
return (texInfos.size() > 0) ? texInfos[texUnit]->getTexRect() : sf::IntRect(0, 0, 0, 0);
}
const Texture* getTexture(int texUnit = 0) {
return (texInfos.size() > 0) ? texInfos[texUnit]->getTexture() : nullptr;
}
std::string getTexId(int texUnit = 0) {
return (texInfos.size() > 0) ? texInfos[texUnit]->getTexId() : nullptr;
}
void setTexId(std::string texId, int texUnit = 0) {
if (texInfos.size() > 0) {
texInfos[texUnit]->setTexId(texId);
}
}
bool useSameTextures (Material& material) {
if (texInfos.size() != material.texInfos.size())
return false;
for (unsigned int i = 0; i < texInfos.size(); i++) {
if (*texInfos[i] != *material.texInfos[i])
return false;
}
return true;
}
bool hasSameColor (Material& material) {
return color == material.color;
}
bool operator== (Material& material) {
return useSameTextures(material) && hasSameColor(material);
}
bool operator!= (Material& material) {
return !useSameTextures(material) || !hasSameColor(material);
}
};
It'll not work because IntRect is not serializable.
For the texture it doesn't matter because I can't send the pointer to the texture directly, but, I send a string instead which tells me which texture to use.
I can make the sf::Texture class serializable and send the image throught the network but I don't thing that's a good idea.
With boost you can add serialization support to SFML classes externally.
template<class Archive>
inline void serialize(Archive& ar, sf::Vector2f& v, const unsigned int version)
{
ar & v.x;
ar & v.y;
}
Yeah I mean serialize images, I've tried a code but it doesn't work.
template<class Archive>
void save(Archive & ar, const unsigned int version) const
{
std::vector<unsigned char> data;
data.assign(m_pixels, m_pixels + sizeof(m_pixels));
std::cout<<"size : "<<data.size()<<std::endl;
ar<<data;
ar<<m_area.left;
ar<<m_area.top;
ar<<m_area.width;
ar<<m_area.height;
ar<<m_size.x;
ar<<m_size.y;
ar<<m_actualSize.x;
ar<<m_actualSize.y;
ar<<m_isSmooth;
ar<<m_isRepeated;
}
template<class Archive>
void load(Archive & ar, const unsigned int version)
{
std::vector<unsigned char> data;
ar>>data;
m_pixels = new sf::Uint8[data.size()];
for (unsigned int i = 0; i < data.size(); i++)
m_pixels[i] = data[i];
ar>>m_area.left;
ar>>m_area.top;
ar>>m_area.width;
ar>>m_area.height;
ar>>m_size.x;
ar>>m_size.y;
ar>>m_actualSize.x;
ar>>m_actualSize.y;
ar>>m_isSmooth;
ar>>m_isRepeated;
loadFromMemory(m_pixels,m_size.x * m_size.y,m_area);
}
BOOST_SERIALIZATION_SPLIT_MEMBER()
And I affect the pointer to the image pixels like this :
// Copy the pixels to the texture, row by row
m_pixels = const_cast<sf::Uint8*> (image.getPixelsPtr() + 4 * (rectangle.left + (width * rectangle.top)));
const sf::Uint8* pixels = (image.getPixelsPtr() + 4 * (rectangle.left + (width * rectangle.top)));
glCheck(glBindTexture(GL_TEXTURE_2D, m_texture));
for (int i = 0; i < rectangle.height; ++i)
{
glCheck(glTexSubImage2D(GL_TEXTURE_2D, 0, 0, i, rectangle.width, 1, GL_RGBA, GL_UNSIGNED_BYTE, pixels));
pixels += 4 * width;
}
But I get a too small size of 8 for the pixels, it seems it doesn't keep all the pixels of the image, should I do the serialization int he class image instead ?