Merci pour les réponses Eroy, G. et pour les détails Laurent !
Voici donc les sources de cette classe NinePatch que je viens de créer pou gérer ces images, que je dois donc maintenant optimiser un peu ( notamment pour gérer les zoom <1 ) :
NinePatch.h/*
* NinePatch.h
*
* Created on: 8 mai 2013
* Author: Dragonic
*/
#ifndef NINEPATCH_H_
#define NINEPATCH_H_
#include <SFML/Window.hpp>
#include <SFML/Graphics.hpp>
#include <iostream>
#include <string>
class NinePatch
{
public:
NinePatch(std::string url);
void draw(sf::Vector2f pos, sf::Vector2f size, sf::RenderWindow &window);
sf::Texture getTextureResize(sf::Vector2f size);
sf::Texture getSourceTexture()
{
sf::IntRect rect=sf::IntRect(1, 1, m_width, m_height);
sf::Sprite sprite=sf::Sprite(m_texture, rect);
return *sprite.getTexture();
}
sf::Texture getSourceTextureFull()
{
return m_texture;
}
protected:
private:
sf::Sprite m_subImages[9];
sf::Texture m_texture;
sf::IntRect m_rect[9];
unsigned int m_width;
unsigned int m_height;
};
#endif /* NINEPATCH_H_ */
NinePatch.cpp/*
* NinePatch.cpp
*
* Created on: 9 mai 2013
* Author: Dragonic
*/
#include "NinePatch.h"
NinePatch::NinePatch(std::string url)
{
sf::Image image;
if (!image.loadFromFile(url))
{
std::cout<<"error chargement image NinePatch"<<std::endl;
}
m_texture.loadFromImage(image);
unsigned int w=image.getSize().x;
unsigned int h=image.getSize().y;
m_width = w-2;
m_height = h-2;
unsigned int x1=0;
unsigned int y1=0;
unsigned int x2=w-1;
unsigned int y2=h-1;
while((image.getPixel(x1, 0)) != sf::Color::Black)//on cherche le 1er pixel non transparent
{
x1++;
}
if(x1!=x2)
{
while((image.getPixel(x2, 0)) != sf::Color::Black)
{
x2--;
}
}
while((image.getPixel(0, y1)) != sf::Color::Black)
{
y1++;
}
if(y1!=y2)
{
while((image.getPixel(0, y2)) != sf::Color::Black)
{
y2--;
}
}
if(x1==x2 && y1==y2)//aucune ligne trouvé
{
std::cout<<"error NinePatch non configuré"<<std::endl;
}
m_rect[0]=sf::IntRect(1, 1, x1, y1);
m_subImages[0]=sf::Sprite(m_texture, m_rect[0]);
m_rect[1]=sf::IntRect(1+x1, 1, x2-x1-1, y1);
m_subImages[1]=sf::Sprite(m_texture, m_rect[1]);
m_rect[2]=sf::IntRect(1+x2, 1, w-x2-2, y1);
m_subImages[2]=sf::Sprite(m_texture, m_rect[2]);
m_rect[3]=sf::IntRect(1, 1+y1, x1, y2-y1);
m_subImages[3]=sf::Sprite(m_texture, m_rect[3]);
m_rect[4]=sf::IntRect(1+x1, 1+y1, x2-x1-1, y2-y1);
m_subImages[4]=sf::Sprite(m_texture, m_rect[4]);
m_rect[5]=sf::IntRect(1+x2, 1+y1, w-x2-2, y2-y1);
m_subImages[5]=sf::Sprite(m_texture, m_rect[5]);
m_rect[6]=sf::IntRect(1, 1+y2, x1, h-y2-2);
m_subImages[6]=sf::Sprite(m_texture, m_rect[6]);
m_rect[7]=sf::IntRect(1+x1, 1+y2, x2-x1-1, h-y2-2);
m_subImages[7]=sf::Sprite(m_texture, m_rect[7]);
m_rect[8]=sf::IntRect(1+x2, 1+y2, w-x2-2, h-y2-2);
m_subImages[8]=sf::Sprite(m_texture, m_rect[8]);
};
void NinePatch::draw(sf::Vector2f pos, sf::Vector2f size, sf::RenderWindow &window)
{
float wScale = (size.x - m_rect[0].width - m_rect[2].width) / m_rect[1].width;
float hScale = (size.y - m_rect[0].height - m_rect[6].height) / m_rect[3].height;
sf::Sprite subImages[9];
for(int i=0;i<9;i++)
{
subImages[i]=m_subImages[i];
}
subImages[0].setPosition(pos);
window.draw(subImages[0]);
subImages[1].setPosition(pos.x+m_rect[0].width, pos.y);
subImages[1].setScale(wScale,1);
window.draw(subImages[1]);
subImages[2].setPosition(pos.x+m_rect[0].width+m_rect[1].width*wScale, pos.y);
window.draw(subImages[2]);
subImages[3].setPosition(pos.x, pos.y+m_rect[0].height);
subImages[3].setScale(1,hScale);
window.draw(subImages[3]);
subImages[4].setPosition(pos.x+m_rect[3].width, pos.y+m_rect[1].height);
subImages[4].setScale(wScale,hScale);
window.draw(subImages[4]);
subImages[5].setPosition(pos.x+m_rect[3].width+m_rect[4].width*wScale, pos.y+m_rect[2].height);
subImages[5].setScale(1,hScale);
window.draw(subImages[5]);
subImages[6].setPosition(pos.x, pos.y+m_rect[0].height+m_rect[3].height*hScale);
window.draw(subImages[6]);
subImages[7].setPosition(pos.x+m_rect[6].width, pos.y+m_rect[1].height+m_rect[4].height*hScale);
subImages[7].setScale(wScale,1);
window.draw(subImages[7]);
subImages[8].setPosition(pos.x+m_rect[6].width+m_rect[7].width*wScale, pos.y+m_rect[2].height+m_rect[5].height*hScale);
window.draw(subImages[8]);
}
sf::Texture NinePatch::getTextureResize(sf::Vector2f size)
{
float wScale = (size.x - m_rect[0].width - m_rect[2].width) / m_rect[1].width;
float hScale = (size.y - m_rect[0].height - m_rect[6].height) / m_rect[3].height;
sf::Sprite subImages[9];
for(int i=0;i<9;i++)
{
subImages[i]=m_subImages[i];
}
sf::RenderTexture renderTexture;
renderTexture.create(size.x,size.y);
renderTexture.clear(sf::Color::Transparent);
subImages[0].setPosition(0,0);
renderTexture.draw(subImages[0]);
subImages[1].setPosition(0+m_rect[0].width, 0);
subImages[1].setScale(wScale,1);
renderTexture.draw(subImages[1]);
subImages[2].setPosition(0+m_rect[0].width+m_rect[1].width*wScale, 0);
renderTexture.draw(subImages[2]);
subImages[3].setPosition(0, 0+m_rect[0].height);
subImages[3].setScale(1,hScale);
renderTexture.draw(subImages[3]);
subImages[4].setPosition(0+m_rect[3].width, 0+m_rect[1].height);
subImages[4].setScale(wScale,hScale);
renderTexture.draw(subImages[4]);
subImages[5].setPosition(0+m_rect[3].width+m_rect[4].width*wScale, 0+m_rect[2].height);
subImages[5].setScale(1,hScale);
renderTexture.draw(subImages[5]);
subImages[6].setPosition(0, 0+m_rect[0].height+m_rect[3].height*hScale);
renderTexture.draw(subImages[6]);
subImages[7].setPosition(0+m_rect[6].width, 0+m_rect[1].height+m_rect[4].height*hScale);
subImages[7].setScale(wScale,1);
renderTexture.draw(subImages[7]);
subImages[8].setPosition(0+m_rect[6].width+m_rect[7].width*wScale, 0+m_rect[2].height+m_rect[5].height*hScale);
renderTexture.draw(subImages[8]);
renderTexture.display();
return renderTexture.getTexture();
}
Et un exemple d'utilisation :
window.clear(sf::Color::White);
NinePatch ninePatch("resources/btn.9.png");
ninePatch.draw(sf::Vector2f(200,200),sf::Vector2f(200,100),window);
sf::Sprite sprite2;
sf::Texture texture2;
texture2 = ninePatch.getTextureResize(sf::Vector2f(100,300));
sprite2.setTexture(texture2);
sprite2.setPosition(50,10);
window.draw(sprite2);
sf::Sprite sprite3;
sf::Texture texture3;
texture3 = ninePatch.getSourceTexture();
sprite3.setTexture(texture3);
sprite3.setPosition(200,10);
window.draw(sprite3);
sf::Sprite sprite4;
sf::Texture texture4;
texture4 = ninePatch.getSourceTextureFull();
sprite4.setTexture(texture4);
sprite4.setPosition(350,10);
window.draw(sprite4);
ce code fourni le résultat suivant :
Et si vous voulez l'image source btn.9.png :
Alors ce qu'il faut savoir, c'est qu'une image de type NinePatch, c'est une image avec une ligne de pixel en plus de chaque côté pour définir les règles de redimensionnement et de contenu. En haut et à gauche les traits noirs définissent les zones ayant le droit d'être redimensionnées.
Je n'ai pas encore rajouter la fonctionnalité pour les lignes à mettre à droite et en bas, qui définissent la zone de contenu, bien pratique pour ensuite placer des éléments (texte ou autre) dans la texture redimensionnée. Néanmoins donc il faut bien rajouter une ligne de pixel à droite et en bas quand même par défaut pour que le NinePatch soit correct.
Enfin bref, pour l'instant les résultats produits me suffisent ^^ !