Welcome, Guest. Please login or register. Did you miss your activation email?

Author Topic: Make the class serializable.  (Read 4432 times)

0 Members and 1 Guest are viewing this topic.

Lolilolight

  • Hero Member
  • *****
  • Posts: 1232
    • View Profile
Make the class serializable.
« on: July 23, 2014, 06:51:59 pm »
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.

Laurent

  • Administrator
  • Hero Member
  • *****
  • Posts: 32504
    • View Profile
    • SFML's website
    • Email
Re: Make the class serializable.
« Reply #1 on: July 23, 2014, 07:19:09 pm »
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;
}
Laurent Gomila - SFML developer

select_this

  • Full Member
  • ***
  • Posts: 130
  • Current mood: just ate a pinecone
    • View Profile
    • darrenferrie.com
Re: Make the class serializable.
« Reply #2 on: July 23, 2014, 07:36:37 pm »
One small warning about Boost serialization, coming from experience: data serialized with one version of the library may not necessarily compatible with applications using a different version (e.g. data serialized with Boost 1.50 may not be readable in an application using Boost 1.54). It's something to bear in mind if you save the serialized data to disk or send it out over a socket etc.
Follow me on Twitter, why don'tcha? @select_this

Lolilolight

  • Hero Member
  • *****
  • Posts: 1232
    • View Profile
Re: Make the class serializable.
« Reply #3 on: July 23, 2014, 09:14:11 pm »
Ok ty I just want to send it through a socket..., mmm..., I just have to convert the special SFML type (Uint8) to a compatible type.

Laurent

  • Administrator
  • Hero Member
  • *****
  • Posts: 32504
    • View Profile
    • SFML's website
    • Email
Re: Make the class serializable.
« Reply #4 on: July 23, 2014, 09:55:03 pm »
Uint8 is just a typedef to unsigned char.
Laurent Gomila - SFML developer

Lolilolight

  • Hero Member
  • *****
  • Posts: 1232
    • View Profile
Re: Make the class serializable.
« Reply #5 on: July 25, 2014, 10:21:55 pm »
Ok, but if one day I want to serialize textures to make a very very light client..., is it possible ?

Laurent

  • Administrator
  • Hero Member
  • *****
  • Posts: 32504
    • View Profile
    • SFML's website
    • Email
Re: Make the class serializable.
« Reply #6 on: July 25, 2014, 11:59:35 pm »
Why not?

And you wouldn't serialize textures anyway, but images.
Laurent Gomila - SFML developer

Lolilolight

  • Hero Member
  • *****
  • Posts: 1232
    • View Profile
Re: Make the class serializable.
« Reply #7 on: July 26, 2014, 10:12:21 am »
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 ?

Lolilolight

  • Hero Member
  • *****
  • Posts: 1232
    • View Profile
Re: Make the class serializable.
« Reply #8 on: July 26, 2014, 11:17:59 am »
Yep! :P

I've serialized the pixels in the class Image and it works, I think I'll do it for every resource. (excepts for musics because we cannot load the entire files)