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

Author Topic: 9 Slice Scaling  (Read 7458 times)

0 Members and 1 Guest are viewing this topic.

GodwinneLorayne

  • Newbie
  • *
  • Posts: 1
    • View Profile
9 Slice Scaling
« on: November 15, 2013, 11:14:34 pm »
I've been using SFML for a few weeks now, and I'm extremely happy with the interfaces you've managed to present, covering such a wide range of tasks. I really want to continue using this library for the foreseeable future, and I'm moving towards build a user interface library on top of it, for consumption in some of my other projects. Currently the feature I would like the most would be slice scaling for Sprites, to more easily create GUI backgrounds.

An example:
http://rwillustrator.blogspot.ca/2007/04/understanding-9-slice-scaling.html

Nexus

  • SFML Team
  • Hero Member
  • *****
  • Posts: 6287
  • Thor Developer
    • View Profile
    • Bromeon
Re: 9 Slice Scaling
« Reply #1 on: November 15, 2013, 11:20:22 pm »
This kind of feature is usually too high-level to be integrated into SFML itself. But you could have a look at the existing GUI libraries for SFML, such as SFGUI or TGUI. They might have already implemented something similar.
Zloxx II: action platformer
Thor Library: particle systems, animations, dot products, ...
SFML Game Development:

Canadadry

  • Hero Member
  • *****
  • Posts: 1081
    • View Profile
Re: 9 Slice Scaling
« Reply #2 on: November 16, 2013, 10:11:26 am »
You don't need anything more from SFML. You can write it pretty easily like this :

headers
#ifndef BORDERIMAGE_H_
#define BORDERIMAGE_H_

namespace sf{
class Texture;
class Color;
}

#include <SFML/Graphics/Transformable.hpp>
#include <SFML/Graphics/Drawable.hpp>
#include <SFML/Graphics/VertexArray.hpp>


class BorderImage : public sf::Drawable, public sf::Transformable
{
public:
        BorderImage();
        virtual ~BorderImage();


        sf::Vector2u getSize() const;
        void setSize(sf::Vector2u size);
        void setWidth(unsigned int width);
        void setHeight(unsigned int height);

        void setTexture(const sf::Texture& texture, unsigned int border);

        void setLeftBorder  (unsigned int leftBorder);
        void setRightBorder (unsigned int rightBorder);
        void setTopBorder   (unsigned int upBorder);
        void setBottomBorder(unsigned int downBorder);
        unsigned int   leftBorder() const;
        unsigned int  rightBorder() const;
        unsigned int    topBorder() const;
        unsigned int bottomBorder() const;

        void setColor(const sf::Color& color);
        sf::Color color() const;

private:
        const sf::Texture* m_texture;
        unsigned int m_left;
        unsigned int m_right;
        unsigned int m_top;
        unsigned int m_bottom;
        unsigned int m_width;
        unsigned int m_height;

        mutable sf::VertexArray    m_vertex_array;
        mutable bool m_need_update;

        void updateVertices() const;
        virtual void draw(sf::RenderTarget& target, sf::RenderStates states) const;

};

#endif /* BORDERIMAGE_H_ */

source
#include "BorderImage.h"


#include <SFML/Graphics/RenderTarget.hpp>
#include <SFML/Graphics/Texture.hpp>

BorderImage::BorderImage()
    : m_texture(0)
    , m_left(0)
    , m_right(0)
    , m_top(0)
    , m_bottom(0)
    , m_width(0)
    , m_height(0)
    , m_need_update(true)
    , m_vertex_array(sf::TrianglesStrip, 24)
{
}

BorderImage::~BorderImage()
{
}

sf::Vector2u BorderImage::getSize() const
{
    return sf::Vector2u(m_width,m_height);
}

void BorderImage::setSize(sf::Vector2u size)
{
    m_width  = size.x;
    m_height = size.y;
    m_need_update = true;
}

void BorderImage::setWidth(unsigned int width)
{
    m_width  = width;
    m_need_update = true;
}

void BorderImage::setHeight(unsigned int height)
{
    m_height = height;
    m_need_update = true;
}

void BorderImage::setTexture(const sf::Texture& texture, unsigned int border)
{
    m_left = border;
    m_right = border;
    m_top = border;
    m_bottom = border;
    m_texture = &texture;
    m_need_update = true;
}

void BorderImage::setLeftBorder (unsigned int border)
{
    m_left = border;
    m_need_update = true;
}

void BorderImage::setRightBorder(unsigned int border)
{
    m_right = border;
    m_need_update = true;
}

void BorderImage::setTopBorder   (unsigned int border)
{
    m_top = border;
    m_need_update = true;
}

void BorderImage::setBottomBorder (unsigned int border)
{
    m_bottom = border;
    m_need_update = true;
}

unsigned int  BorderImage::leftBorder() const  { return m_left;  }
unsigned int BorderImage::rightBorder() const  { return m_right; }
unsigned int    BorderImage::topBorder() const  { return m_top;   }
unsigned int  BorderImage::bottomBorder() const { return m_bottom;}


void BorderImage::setColor(const sf::Color& color)
{
    for(int i=0;i<24;i++)
    {
        m_vertex_array[ i].color = color;
    }
}

void BorderImage::draw(sf::RenderTarget& target,sf::RenderStates states) const
{
    if( m_need_update == true)
    {
        updateVertices();
        m_need_update = false;
    }
    if (m_texture)
    {
        states.transform *= getTransform();
        states.texture = m_texture;
        target.draw(m_vertex_array,states);
    }
}

void BorderImage::updateVertices() const
{
    // http://dan.lecocq.us/wordpress/wp-content/uploads/2009/12/strip.png
    //     i ->
    //   j  0     1    2    3
    //   |
    //   V  4     5    6    7
    //
    //      8     9    10   11
    //
    //     12    13    14   15
    //
    // =>       0, 4, 1, 5, 2, 6, 3, 7, 7, 11, 6, 10, 5, 9 ,4 ,8, 8 ,12 ,9 ,13, 10 ,14, 11,15

    const unsigned int triangleStripVextexCount = 24;
    const unsigned int triangleStripVertexOrder[triangleStripVextexCount] = {0, 4, 1, 5, 2, 6, 3, 7, 7, 11, 6, 10, 5, 9 ,4 ,8, 8 ,12 ,9 ,13, 10 ,14, 11,15};

    if (m_texture)
    {
        unsigned int x_pos[4] = {0 , m_left , m_width  - m_right  , m_width};
        unsigned int y_pos[4] = {0 , m_top  , m_height - m_bottom , m_height};
        sf::Vector2f verticesPosition[16];

        unsigned int t_width = m_texture->getSize().x;
        unsigned int t_height = m_texture->getSize().x;

        unsigned int x_textCoord[4] = {0,m_left , t_width  - m_right  , t_width};
        unsigned int y_textCoord[4] = {0,m_top  , t_height - m_bottom , t_height};
        sf::Vector2f verticesTextCoord[16];

        for(int i = 0; i< 4;i++)
        {
            for(int j = 0; j< 4;j++)
            {
                verticesPosition[i+4*j] = sf::Vector2f(x_pos[i],y_pos[j]);
                verticesTextCoord[i+4*j] = sf::Vector2f(x_textCoord[i],y_textCoord[j]);
            }
        }

        for(int i = 0; i<triangleStripVextexCount;i++)
        {
            m_vertex_array[ i].position  = verticesPosition [ triangleStripVertexOrder[i]];
            m_vertex_array[ i].texCoords = verticesTextCoord[ triangleStripVertexOrder[i]];
        }
    }
}
 

wintertime

  • Sr. Member
  • ****
  • Posts: 255
    • View Profile
Re: 9 Slice Scaling
« Reply #3 on: November 16, 2013, 02:48:58 pm »
I wondered what this magic 9 Slice Scaling was, took a short look at the article late at night, did not see what that special thing was besides clicking something in a drawing program.
Then I carefully read it today. And found it is only about advising people of wasting space in textures duplicating things and including a huge empty client area inside, by not making a decent texture with separate edge, corner, T junction and + tiles (and maybe a background tile and all those other things like buttons, title bars and so on, too) for their GUI? :'(

Mario

  • SFML Team
  • Hero Member
  • *****
  • Posts: 879
    • View Profile
Re: 9 Slice Scaling
« Reply #4 on: November 17, 2013, 10:16:40 pm »
No. It's usually really just making a minimal texture that supports tiling or stretching. Based on your design you might not need all 9 different tiles, true, but it's far from "obsolete" or anything. And how is it wasting space? The example images on the blog are horrible, cause the top looks like the bottom and the left looks light the right, but those might indeed be different (e.g. different shading or different colors).

However, I'd most likely use pixel shaders for this, unless the target platform doesn't support them or would be rather slow using them.