Hi Naphier,
I currently don't use the uv for the edges but I plan to implement it soon. At the moment I stretch them in one direction which means you are limited to how then look but they can be any size. Manipulating an edge pattern with uv coordinates will mean you can have more varied frames but you may need to snap them to the nearest size to get a seamless join.
Here is my Frame class, it is built on top of an Entity2 class, not sure this will be any use to you but here it is:
#ifndef ELE_GUI_FRAME
#define ELE_GUI_FRAME
#include "../include/gui/Frame.h"
using namespace ele;
using namespace gui;
Frame::Frame(){}
Frame::Frame(const Vec2 &size, Skin *skin, Entity2* parent, int frameType) : Entity2(parent), _skin(skin)
{
_frameType = frameType;
//-- Top Left
//if(_arrId[0])
_arrId[0] = agk::CreateSprite(skin->getImage(Skin::SKIN_CORNER));//skin->_imgCorner);
//-- Top Join
//if(_arrId[1])
_arrId[1] = agk::CreateSprite(skin->getImage(Skin::SKIN_JOIN_HOR));//skin->_imgJoin);
//-- Top Right
_arrId[2] = agk::CreateSprite(skin->getImage(Skin::SKIN_CORNER));//skin->_imgCorner);
agk::SetSpriteFlip(_arrId[2], 1, 0);
//-- Left Join
_arrId[3] = agk::CreateSprite(skin->getImage(Skin::SKIN_JOIN_VERT));//skin->_imgJoinV);
//-- Right Join
_arrId[4] = agk::CreateSprite(skin->getImage(Skin::SKIN_JOIN_VERT));//skin->_imgJoinV);
agk::SetSpriteFlip(_arrId[4], 1, 0);
//-- Bottom Left
_arrId[5] = agk::CreateSprite(skin->getImage(Skin::SKIN_CORNER));//skin->_imgCorner);
agk::SetSpriteFlip(_arrId[5], 0, 1);
//-- Bottom Join
_arrId[6] = agk::CreateSprite(skin->getImage(Skin::SKIN_JOIN_HOR));//skin->_imgJoin);
agk::SetSpriteFlip(_arrId[6], 0, 1);
//-- Top Right
_arrId[7] = agk::CreateSprite(skin->getImage(Skin::SKIN_CORNER));//skin->_imgCorner);
agk::SetSpriteFlip(_arrId[7], 1, 1);
//-- Back
_arrId[8] = agk::CreateSprite(skin->getImage(Skin::SKIN_CENTRE_BACK));//skin->_imgBack);
////-- Facia
//_arrId[9] = agk::CreateSprite(skin->getImage(Skin::SKIN_CORNER_FACIA));//skin->_imgCornerFacia);
//_arrId[10] = agk::CreateSprite(skin->getImage(Skin::SKIN_CORNER_FACIA));//skin->_imgCornerFacia);
//agk::SetSpriteFlip(_arrId[10], 1, 0);
//_arrId[11] = agk::CreateSprite(skin->getImage(Skin::SKIN_JOIN_HOR_FACIA));//skin->_imgJoinFacia);
Vec2 dim = size * _screenDim;
//size = size * _screenDim;
for(unsigned int i = 0; i < 9; i++)
{
//-- Once set, the corner sprites never change size,
//-- not from inside gui system anyway, you can alter the
//-- size manually, but should not be needed.
//agk::SetSpriteSize(_arrId[i], size._x, size._y);
agk::SetSpriteSize(_arrId[i], dim._x, dim._y);
agk::SetSpriteUVBorder(_arrId[i], 1.0f);
}
float sprWidth = agk::GetSpriteWidth(_arrId[0]);
float sprHeight = agk::GetSpriteHeight(_arrId[0]);
_relCornerSize = ele::Vec2(sprWidth, sprHeight) / _screenDim;
//-- if frame is outside content box then we need to update hit boundary
//-- or nothing will be detected outside content
if(_frameType == FRAME_OUT)
setBoundary(Vec4(-sprWidth, -sprHeight, sprWidth, sprHeight));
//update();
}
Frame::~Frame()
{
for(unsigned int i = 0; i < 9; i++)
{
agk::DeleteSprite(_arrId[i]);
}
}
void Frame::setSkin(Skin* skin)
{
//-- Top Left
if(_arrId[0] && skin->getImage(Skin::SKIN_CORNER))
agk::SetSpriteImage(_arrId[0], skin->getImage(Skin::SKIN_CORNER));//skin->_imgCorner);
//-- Top Join
if(_arrId[1] && skin->getImage(Skin::SKIN_JOIN_HOR))
agk::SetSpriteImage(_arrId[1], skin->getImage(Skin::SKIN_JOIN_HOR));//skin->_imgJoin);
//-- Top Right
if(_arrId[2] && skin->getImage(Skin::SKIN_CORNER))
agk::SetSpriteImage(_arrId[2], skin->getImage(Skin::SKIN_CORNER));//skin->_imgCorner);
//agk::SetSpriteFlip(_arrId[2], 1, 0);
//-- Left Join
if(_arrId[3] && skin->getImage(Skin::SKIN_JOIN_VERT))
agk::SetSpriteImage(_arrId[3], skin->getImage(Skin::SKIN_JOIN_VERT));//skin->_imgJoinV);
//-- Right Join
if(_arrId[4] && skin->getImage(Skin::SKIN_JOIN_VERT))
agk::SetSpriteImage(_arrId[4], skin->getImage(Skin::SKIN_JOIN_VERT));//skin->_imgJoinV);
//agk::SetSpriteFlip(_arrId[4], 1, 0);
//-- Bottom Left
if(_arrId[5] && skin->getImage(Skin::SKIN_CORNER))
agk::SetSpriteImage(_arrId[5], skin->getImage(Skin::SKIN_CORNER));//skin->_imgCorner);
//agk::SetSpriteFlip(_arrId[5], 0, 1);
//-- Bottom Join
if(_arrId[6] && skin->getImage(Skin::SKIN_JOIN_HOR))
agk::SetSpriteImage(_arrId[6], skin->getImage(Skin::SKIN_JOIN_HOR));//skin->_imgJoin);
//agk::SetSpriteFlip(_arrId[6], 0, 1);
//-- Top Right
if(_arrId[7] && skin->getImage(Skin::SKIN_CORNER))
agk::SetSpriteImage(_arrId[7], skin->getImage(Skin::SKIN_CORNER));//skin->_imgCorner);
//agk::SetSpriteFlip(_arrId[7], 1, 1);
//-- Back
if(_arrId[8] && skin->getImage(Skin::SKIN_CENTRE_BACK))
agk::SetSpriteImage(_arrId[8], skin->getImage(Skin::SKIN_CENTRE_BACK));//skin->_imgBack);
////-- Facia
//if(_arrId[9] && skin->getImage(Skin::SKIN_CORNER_FACIA))
// agk::SetSpriteImage(_arrId[9], skin->getImage(Skin::SKIN_CORNER_FACIA));//skin->_imgCornerFacia);
//if(_arrId[10] && skin->getImage(Skin::SKIN_CORNER_FACIA))
// agk::SetSpriteImage(_arrId[10], skin->getImage(Skin::SKIN_CORNER_FACIA));//skin->_imgCornerFacia);
////agk::SetSpriteFlip(_arrId[10], 1, 0);
//if(_arrId[11] && skin->getImage(Skin::SKIN_JOIN_HOR_FACIA))
// agk::SetSpriteImage(_arrId[11], skin->getImage(Skin::SKIN_JOIN_HOR_FACIA));//skin->_imgJoinFacia);
}
void Frame::update()
{
if(_frameType == FRAME_OUT)
{
updateFrameOut();
}
else if(_frameType == FRAME_IN)
{
updateFrameIn();
}
}
void Frame::updateFrameIn()
{
Vec2 pos = getPosAbs();
Vec2 dim = getDimAbs();
pos = pos * _screenDim;
dim = dim * _screenDim;
float sprWidth = agk::GetSpriteWidth(_arrId[0]);
float joinH = dim._x - sprWidth * 2;
if(joinH < 0.01)
{
dim._x = sprWidth * 2;
joinH = 0.01f;
}
float sprHeight = agk::GetSpriteHeight(_arrId[0]);
float joinV = dim._y - sprHeight * 2;
if(joinV < 0.01)
{
dim._y = sprHeight * 2;
joinV = 0.01f;
}
_relCornerSize = ele::Vec2(sprWidth, sprHeight) / _screenDim;
//-- Top Left
agk::SetSpritePosition(_arrId[0], pos._x, pos._y);
//-- Facia
//agk::SetSpritePosition(_arrId[9], pos._x, pos._y);
//-- Top Join
agk::SetSpritePosition(_arrId[1], pos._x + sprWidth, pos._y);
//-- Facia
//agk::SetSpritePosition(_arrId[11], pos._x + sprWidth, pos._y);
//-- Top Right
agk::SetSpritePosition(_arrId[2], pos._x + sprWidth + joinH, pos._y);
//agk::SetSpritePosition(_arrId[10], pos._x + sprWidth + joinH, pos._y);
//-- Left Join
agk::SetSpritePosition(_arrId[3], pos._x, pos._y + sprHeight);
//-- Right Join
agk::SetSpritePosition(_arrId[4], pos._x + sprWidth + joinH , pos._y + sprHeight);
//-- Bottom Left
agk::SetSpritePosition(_arrId[5], pos._x, pos._y + sprHeight + joinV);
//-- Bottom Join
agk::SetSpritePosition(_arrId[6], pos._x + sprWidth, pos._y + sprHeight + joinV);
//-- Top Right
agk::SetSpritePosition(_arrId[7], pos._x + sprWidth + joinH, pos._y + sprHeight + joinV);
//-- Back
agk::SetSpritePosition(_arrId[8], pos._x + sprWidth, pos._y + sprHeight);
//-- Top Left
//-- Top Join
agk::SetSpriteSize(_arrId[1], joinH, sprHeight);
//-- Facia
//agk::SetSpriteSize(_arrId[11], joinH, sprHeight);
//-- Top Right
//-- Left Join
agk::SetSpriteSize(_arrId[3], sprWidth, joinV);
//-- Right Join
agk::SetSpriteSize(_arrId[4], sprWidth, joinV);
//-- Bottom Left
//-- Bottom Join
agk::SetSpriteSize(_arrId[6], joinH, sprHeight);
//-- Top Right
//-- Back
agk::SetSpriteSize(_arrId[8], joinH, joinV);
//-- UVs
float u = sprWidth / joinH;
float v = sprHeight / joinV;
//-- Joins
agk::SetSpriteUVScale(_arrId[1], u, 1.0f);
agk::SetSpriteUVScale(_arrId[3], 1.0f, v);
agk::SetSpriteUVScale(_arrId[4], 1.0f, v);
agk::SetSpriteUVScale(_arrId[6], u, 1.0f);
//-- Back
agk::SetSpriteUVScale(_arrId[8], u, v);
int depth = getDepth();
//-- Depth
for(unsigned int i = 0; i < 9; i++)
{
agk::SetSpriteDepth(_arrId[i], getDepth());//_depth);
}
////-- facia
//for(unsigned int i = 9; i < 12; i++)
//{
// agk::SetSpriteDepth(_arrId[i], getDepth() - 1);//_depth - 10);
//}
}
void Frame::updateFrameOut()
{
//-- Frame dim is measured by back panel only, the edges are placed around outside the entity
//-- this is for neat alignment when adding child buttons etc
//-- Note, add a function to get/set from visible dimensions!
Vec2 pos = getPosAbs();
Vec2 dim = getDimAbs();
pos = pos * _screenDim;
dim = dim * _screenDim;
float sprWidth = agk::GetSpriteWidth(_arrId[0]);
float joinH = dim._x;// - sprWidth * 2;
if(joinH < 0.01)
{
dim._x = sprWidth * 2;
joinH = 0.01f;
}
float sprHeight = agk::GetSpriteHeight(_arrId[0]);
float joinV = dim._y;// - sprHeight * 2;
if(joinV < 0.01)
{
dim._y = sprHeight * 2;
joinV = 0.01f;
}
_relCornerSize = ele::Vec2(sprWidth, sprHeight) / _screenDim;
//-- Top Left
agk::SetSpritePosition(_arrId[0], pos._x - sprWidth, pos._y - sprHeight);
//-- Facia
//agk::SetSpritePosition(_arrId[9], pos._x - sprWidth, pos._y - sprHeight);
//-- Top Join
agk::SetSpritePosition(_arrId[1], pos._x, pos._y - sprHeight);
//-- Facia
//agk::SetSpritePosition(_arrId[11], pos._x, pos._y - sprHeight);
//-- Top Right
agk::SetSpritePosition(_arrId[2], pos._x + joinH, pos._y - sprHeight);
//agk::SetSpritePosition(_arrId[10], pos._x + joinH, pos._y - sprHeight);
//-- Left Join
agk::SetSpritePosition(_arrId[3], pos._x - sprWidth, pos._y);
//-- Right Join
agk::SetSpritePosition(_arrId[4], pos._x + joinH , pos._y);
//-- Bottom Left
agk::SetSpritePosition(_arrId[5], pos._x - sprWidth, pos._y + joinV);
//-- Bottom Join
agk::SetSpritePosition(_arrId[6], pos._x, pos._y + joinV);
//-- Bottom Right
agk::SetSpritePosition(_arrId[7], pos._x + joinH, pos._y + joinV);
//-- Back
agk::SetSpritePosition(_arrId[8], pos._x, pos._y);
//-- Top Left
//-- Top Join
agk::SetSpriteSize(_arrId[1], joinH, sprHeight);
//-- Facia
//agk::SetSpriteSize(_arrId[11], joinH, sprHeight);
//-- Top Right
//-- Left Join
agk::SetSpriteSize(_arrId[3], sprWidth, joinV);
//-- Right Join
agk::SetSpriteSize(_arrId[4], sprWidth, joinV);
//-- Bottom Left
//-- Bottom Join
agk::SetSpriteSize(_arrId[6], joinH, sprHeight);
//-- Top Right
//-- Back
agk::SetSpriteSize(_arrId[8], joinH, joinV);
//-- UVs
float u = sprWidth / joinH;
float v = sprHeight / joinV;
//-- Joins
agk::SetSpriteUVScale(_arrId[1], u, 1.0f);
agk::SetSpriteUVScale(_arrId[3], 1.0f, v);
agk::SetSpriteUVScale(_arrId[4], 1.0f, v);
agk::SetSpriteUVScale(_arrId[6], u, 1.0f);
//-- Back
agk::SetSpriteUVScale(_arrId[8], u, v);
//int depth = getDepth();
//-- Depth
for(unsigned int i = 0; i < 9; i++)
{
agk::SetSpriteDepth(_arrId[i], getDepth());//_depth);
}
//-- facia
//for(unsigned int i = 9; i < 12; i++)
//{
// agk::SetSpriteDepth(_arrId[i], getDepth() - 1);//_depth - 10);
//}
}
void Frame::setVisible(int visible)
{
for(unsigned int i = 0; i < 9; i++) //-- was 12
{
agk::SetSpriteVisible(_arrId[i], visible);//_depth - 10);
}
Entity2::setVisible(visible);
}
void Frame::setColour(int r, int g, int b, int a)
{
for(unsigned int i = 0; i < 9; i++) //-- was 12
{
agk::SetSpriteColor(_arrId[i], r, g, b, a);//_depth - 10);
}
}
ele::Vec2 Frame::getCornerDimRel()
{
return _relCornerSize;
}
void Frame::debugDrawLine(const Line2 &line)
{
Line2 lineLoc = line;
lineLoc._src = line._src * _screenDim;
lineLoc._dst = line._dst * _screenDim;
agk::DrawLine(lineLoc._src._x, lineLoc._src._y, lineLoc._dst._x, lineLoc._dst._y, 0, 0, 0);
}
#endif
Some useful things to think about:
You may want to separate how the images are handled, I use a Skin class which holds all the images, my Frame class has a SetSkin() command which changes the look of the Frame.
You should think about defining different edges(borders), there is an outside border which is used when the Frame is placed inside another Frame, but there is also an inside border which is used when putting things inside that frame. Then you may want to have a 'hit' border for detecting touches etc, this may not always correspond with the other borders for various reasons.
You may want to have a DebugDraw() command which draws all the various borders in different colours, it helps when putting ui's together and things don't seem to be working like they should, it allows you to see exactly what is going on.
If you are using tier 2 you can try my ui system if you like? Let me know if you need any more help.