mupilz
13th February 2012, 22:10
Hi,
first what I'm doing.
I'm coding a small GUI system for a game I'm writing. The existing GUI Toolkits usable on Ogre3D don't convince me enought that I use them. I'd like to use Qt, I even tried it but had some major issues doing so (major performance loss, Mouse/Keyboard events not working, etc.). So I decided to write my own toolkit. I already did write one, but it was very dirty and I didn't write it as an own library but coded it directly to the game. So I decided to re-write it.
Now my issue.
When rendering the Widgets, everything is fine, until I add a border radius. I guess, an image showing it is way easier than explaining:
click me (http://ompldr.org/vY3QyNQ)
I'm rendering directly on a QImage, using QPainter/QPainterPath.
The Pen is defined as follows:
painter.setPen(QPen(b, wB, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin));
The Brush is either a QColor or a QLinearGradient.
As render hint I only use Antialiasing.
The QImage is in the ARGB32 format.
I tried both approaches for the border radius, arcTo and cubicTo. Both ways have the same issue.
The problem occurs on different Graphics Systems.
here is the code I use for the rendering:
QImage AWidget::paint()
{
if (!visible())
{
cHasChange = false;
return QImage();
}
if (!hasChange())
{
cHasChange = false;
if (cLastImage != 0)
{
return *cLastImage;
}
}
cHasChange = false;
short w = width();
short h = height();
short radTL = 10;
short radTR = 10;
short radBR = 10;
short radBL = 10;
QBrush bg(QColor(100, 200, 100, 100));
QColor b(0, 0, 0, 255);
short wB = 1;
if (cHasStyle)
{
if (cBorder->radius()->isValid())
{
radTL = cBorder->radius()->tl();
radTR = cBorder->radius()->tr();
radBR = cBorder->radius()->br();
radBL = cBorder->radius()->bl();
}
if (cBackground->color()->isValid())
{
bg = QBrush(cBackground->color()->toQColor());
}
else if (cBackground->gradient()->isValid())
{
bg = QBrush(cBackground->gradient()->toQGradient());
}
if (cBorder->color()->isValid())
{
b = (cBorder->color()->toQColor());
}
if (cBorder->size()->isValid())
{
wB = cBorder->size()->left();
}
}
bool useCubic = false;
QPainterPath path;
path.moveTo(radTL, 0);
path.lineTo(w - radTR, 0);
if (radTR > 0)
{
if (useCubic)
{
path.cubicTo(w, 0, w, radTR, w, radTR);
}
else
{
path.arcTo(w - radTR * 2, 0, radTR * 2, radTR * 2, 90, -90);
}
}
path.lineTo(w, h - radBR);
if (radBR > 0)
{
if (useCubic)
{
path.cubicTo(w, h, w - radBR, h, w - radBR, h);
}
else
{
path.arcTo(w - radBR * 2, h - radBR * 2, radBR * 2, radBR * 2, 0, -90);
}
}
path.lineTo(radBL, h);
if (radBL > 0)
{
if (useCubic)
{
path.cubicTo(0, h, 0, h - radBL, 0, h - radBL);
}
else
{
path.arcTo(0, h - radBL * 2, radBL * 2, radBL * 2, -90, -90);
}
}
path.lineTo(0, radTL);
if (radTL > 0)
{
if (useCubic)
{
path.cubicTo(0, radTL, 0, 0, radTL, 0);
}
else
{
path.arcTo(0, 0, radTL * 2, radTL * 2, -180, -90);
}
}
path.closeSubpath();
QImage *img = new QImage(w, h, QImage::Format_ARGB32);
img->fill(0);
QPainter painter;
painter.begin(img);
painter.setRenderHints(QPainter::Antialiasing);
painter.setPen(QPen(b, wB, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin));
painter.setBrush(bg);
painter.drawPath(path);
paintEvent(&painter);
// +++ draw children
if (children().length() > 0)
{
for (int i = 0; i < children().length(); i++)
{
painter.drawImage(child(i)->x(), child(i)->y(), child(i)->paint());
}
}
// --- draw children
painter.end();
cLastImage = img;
return *img;
}
Furthermore would I like to ask, what the better way to render the border radius is - an arc or a bezier curve?
If some information is missing, feel free to tell.
cheers
first what I'm doing.
I'm coding a small GUI system for a game I'm writing. The existing GUI Toolkits usable on Ogre3D don't convince me enought that I use them. I'd like to use Qt, I even tried it but had some major issues doing so (major performance loss, Mouse/Keyboard events not working, etc.). So I decided to write my own toolkit. I already did write one, but it was very dirty and I didn't write it as an own library but coded it directly to the game. So I decided to re-write it.
Now my issue.
When rendering the Widgets, everything is fine, until I add a border radius. I guess, an image showing it is way easier than explaining:
click me (http://ompldr.org/vY3QyNQ)
I'm rendering directly on a QImage, using QPainter/QPainterPath.
The Pen is defined as follows:
painter.setPen(QPen(b, wB, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin));
The Brush is either a QColor or a QLinearGradient.
As render hint I only use Antialiasing.
The QImage is in the ARGB32 format.
I tried both approaches for the border radius, arcTo and cubicTo. Both ways have the same issue.
The problem occurs on different Graphics Systems.
here is the code I use for the rendering:
QImage AWidget::paint()
{
if (!visible())
{
cHasChange = false;
return QImage();
}
if (!hasChange())
{
cHasChange = false;
if (cLastImage != 0)
{
return *cLastImage;
}
}
cHasChange = false;
short w = width();
short h = height();
short radTL = 10;
short radTR = 10;
short radBR = 10;
short radBL = 10;
QBrush bg(QColor(100, 200, 100, 100));
QColor b(0, 0, 0, 255);
short wB = 1;
if (cHasStyle)
{
if (cBorder->radius()->isValid())
{
radTL = cBorder->radius()->tl();
radTR = cBorder->radius()->tr();
radBR = cBorder->radius()->br();
radBL = cBorder->radius()->bl();
}
if (cBackground->color()->isValid())
{
bg = QBrush(cBackground->color()->toQColor());
}
else if (cBackground->gradient()->isValid())
{
bg = QBrush(cBackground->gradient()->toQGradient());
}
if (cBorder->color()->isValid())
{
b = (cBorder->color()->toQColor());
}
if (cBorder->size()->isValid())
{
wB = cBorder->size()->left();
}
}
bool useCubic = false;
QPainterPath path;
path.moveTo(radTL, 0);
path.lineTo(w - radTR, 0);
if (radTR > 0)
{
if (useCubic)
{
path.cubicTo(w, 0, w, radTR, w, radTR);
}
else
{
path.arcTo(w - radTR * 2, 0, radTR * 2, radTR * 2, 90, -90);
}
}
path.lineTo(w, h - radBR);
if (radBR > 0)
{
if (useCubic)
{
path.cubicTo(w, h, w - radBR, h, w - radBR, h);
}
else
{
path.arcTo(w - radBR * 2, h - radBR * 2, radBR * 2, radBR * 2, 0, -90);
}
}
path.lineTo(radBL, h);
if (radBL > 0)
{
if (useCubic)
{
path.cubicTo(0, h, 0, h - radBL, 0, h - radBL);
}
else
{
path.arcTo(0, h - radBL * 2, radBL * 2, radBL * 2, -90, -90);
}
}
path.lineTo(0, radTL);
if (radTL > 0)
{
if (useCubic)
{
path.cubicTo(0, radTL, 0, 0, radTL, 0);
}
else
{
path.arcTo(0, 0, radTL * 2, radTL * 2, -180, -90);
}
}
path.closeSubpath();
QImage *img = new QImage(w, h, QImage::Format_ARGB32);
img->fill(0);
QPainter painter;
painter.begin(img);
painter.setRenderHints(QPainter::Antialiasing);
painter.setPen(QPen(b, wB, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin));
painter.setBrush(bg);
painter.drawPath(path);
paintEvent(&painter);
// +++ draw children
if (children().length() > 0)
{
for (int i = 0; i < children().length(); i++)
{
painter.drawImage(child(i)->x(), child(i)->y(), child(i)->paint());
}
}
// --- draw children
painter.end();
cLastImage = img;
return *img;
}
Furthermore would I like to ask, what the better way to render the border radius is - an arc or a bezier curve?
If some information is missing, feel free to tell.
cheers