GUI: Add VectorRendererSpec::drawTriangleClip()

This commit is contained in:
Alexander Tkachev 2016-06-29 15:40:37 +06:00 committed by Eugene Sandulenko
parent 5868d6d471
commit 559ca37daf
6 changed files with 338 additions and 9 deletions

View File

@ -187,6 +187,7 @@ public:
* @param orient Orientation of the triangle.
*/
virtual void drawTriangle(int x, int y, int base, int height, TriangleOrientation orient) = 0;
virtual void drawTriangleClip(int x, int y, int base, int height, TriangleOrientation orient, Common::Rect clipping) = 0;
/**
* Draws a beveled square like the ones in the Classic GUI themes.
@ -390,7 +391,7 @@ public:
void drawCallback_TRIANGLE(const Common::Rect &area, const DrawStep &step, const Common::Rect &clip) { //TODO
uint16 x, y, w, h;
stepGetPositions(step, area, x, y, w, h);
drawTriangle(x, y, w, h, (TriangleOrientation)step.extraData);
drawTriangleClip(x, y, w, h, (TriangleOrientation)step.extraData, clip);
}
void drawCallback_BEVELSQ(const Common::Rect &area, const DrawStep &step, const Common::Rect &clip) { //TODO

View File

@ -870,6 +870,13 @@ blendPixelPtr(PixelType *ptr, PixelType color, uint8 alpha) {
}
}
template<typename PixelType>
inline void VectorRendererSpec<PixelType>::
blendPixelPtrClip(PixelType *ptr, PixelType color, uint8 alpha, int x, int y) {
if (IS_IN_CLIP(x, y))
blendPixelPtr(ptr, color, alpha);
}
template<typename PixelType>
inline void VectorRendererSpec<PixelType>::
blendPixelDestAlphaPtr(PixelType *ptr, PixelType color, uint8 alpha) {
@ -1263,8 +1270,88 @@ drawTriangle(int x, int y, int w, int h, TriangleOrientation orient) {
}
}
template<typename PixelType>
void VectorRendererSpec<PixelType>::
drawTriangleClip(int x, int y, int w, int h, TriangleOrientation orient, Common::Rect clipping) {
if (x + w > Base::_activeSurface->w || y + h > Base::_activeSurface->h)
return;
PixelType color = 0;
if (Base::_strokeWidth <= 1) {
if (Base::_fillMode == kFillForeground)
color = _fgColor;
else if (Base::_fillMode == kFillBackground)
color = _bgColor;
} else {
if (Base::_fillMode == kFillDisabled)
return;
color = _fgColor;
}
if (Base::_dynamicData != 0)
orient = (TriangleOrientation)Base::_dynamicData;
Common::Rect backup = _clippingArea;
_clippingArea = clipping;
bool useClippingVersions = !(_clippingArea.isEmpty() || _clippingArea.contains(Common::Rect(x, y, x + w, y + h)));
if (w == h) {
int newW = w;
switch (orient) {
case kTriangleUp:
case kTriangleDown:
if (useClippingVersions)
drawTriangleVertAlgClip(x, y, newW, newW, (orient == kTriangleDown), color, Base::_fillMode);
else
drawTriangleVertAlg(x, y, newW, newW, (orient == kTriangleDown), color, Base::_fillMode);
break;
case kTriangleLeft:
case kTriangleRight:
case kTriangleAuto:
break;
}
if (Base::_strokeWidth > 0)
if (Base::_fillMode == kFillBackground || Base::_fillMode == kFillGradient) {
if (useClippingVersions)
drawTriangleVertAlgClip(x, y, newW, newW, (orient == kTriangleDown), color, Base::_fillMode);
else
drawTriangleVertAlg(x, y, newW, newW, (orient == kTriangleDown), color, Base::_fillMode);
}
} else {
int newW = w;
int newH = h;
switch (orient) {
case kTriangleUp:
case kTriangleDown:
if (useClippingVersions)
drawTriangleVertAlgClip(x, y, newW, newH, (orient == kTriangleDown), color, Base::_fillMode);
else
drawTriangleVertAlg(x, y, newW, newH, (orient == kTriangleDown), color, Base::_fillMode);
break;
case kTriangleLeft:
case kTriangleRight:
case kTriangleAuto:
break;
}
if (Base::_strokeWidth > 0) {
if (Base::_fillMode == kFillBackground || Base::_fillMode == kFillGradient) {
if (useClippingVersions)
drawTriangleVertAlgClip(x, y, newW, newH, (orient == kTriangleDown), _fgColor, kFillDisabled);
else
drawTriangleVertAlg(x, y, newW, newH, (orient == kTriangleDown), _fgColor, kFillDisabled);
}
}
}
_clippingArea = backup;
}
/********************************************************************
@ -1821,6 +1908,212 @@ drawTriangleVertAlg(int x1, int y1, int w, int h, bool inverted, PixelType color
}
/////////////
template<typename PixelType>
void VectorRendererSpec<PixelType>::
drawTriangleVertAlgClip(int x1, int y1, int w, int h, bool inverted, PixelType color, VectorRenderer::FillMode fill_m) {
// Don't draw anything for empty rects. This assures dy is always different
// from zero.
if (w <= 0 || h <= 0) {
return;
}
int pitch = _activeSurface->pitch / _activeSurface->format.bytesPerPixel;
int gradient_h = 0;
int y_pitch_sign = 1;
if (!inverted) {
pitch = -pitch;
y1 += h;
y_pitch_sign = -1;
}
PixelType *ptr_right = (PixelType *)_activeSurface->getBasePtr(x1, y1);
PixelType *floor = ptr_right - 1;
PixelType *ptr_left = (PixelType *)_activeSurface->getBasePtr(x1 + w, y1);
int x2 = x1 + w / 2;
int y2 = y1 + h;
int x_right = x1;
int y_right = y1;
int x_left = x1 + w;
int y_left = y1;
int x_floor = x_right - 1;
int y_floor = y_right;
#if FIXED_POINT
int dx = (x2 - x1) << 8;
int dy = (y2 - y1) << 8;
if (abs(dx) > abs(dy)) {
#else
double dx = (double)x2 - (double)x1;
double dy = (double)y2 - (double)y1;
if (fabs(dx) > fabs(dy)) {
#endif
while (floor++ != ptr_left)
blendPixelPtrClip(floor, color, 50, ++x_floor, y_floor);
#if FIXED_POINT
// In this branch dx is always different from zero. This is because
// abs(dx) is strictly greater than abs(dy), and abs returns zero
// as minimal value.
int gradient = (dy << 8) / dx;
int intery = (y1 << 8) + gradient;
#else
double gradient = dy / dx;
double intery = y1 + gradient;
#endif
for (int x = x1 + 1; x < x2; x++) {
#if FIXED_POINT
if (intery + gradient > ipart(intery) + 0x100) {
#else
if (intery + gradient > ipart(intery) + 1) {
#endif
ptr_right++;
ptr_left--;
++x_right;
--x_left;
}
ptr_left += pitch;
ptr_right += pitch;
y_right += y_pitch_sign;
y_left += y_pitch_sign;
intery += gradient;
switch (fill_m) {
case kFillDisabled:
if (IS_IN_CLIP(x_left, y_left)) *ptr_left = color;
if (IS_IN_CLIP(x_right, y_right)) *ptr_right = color;
break;
case kFillForeground:
case kFillBackground:
colorFillClip<PixelType>(ptr_right + 1, ptr_left, color, x_right+1, y_right, _clippingArea);
blendPixelPtrClip(ptr_right, color, rfpart(intery), x_right, y_right);
blendPixelPtrClip(ptr_left, color, rfpart(intery), x_left, y_left);
break;
case kFillGradient:
colorFillClip<PixelType>(ptr_right, ptr_left, calcGradient(gradient_h++, h), x_right, y_right, _clippingArea);
blendPixelPtrClip(ptr_right, color, rfpart(intery), x_right, y_right);
blendPixelPtrClip(ptr_left, color, rfpart(intery), x_left, y_left);
break;
}
}
return;
}
#if FIXED_POINT
if (abs(dx) < abs(dy)) {
#else
if (fabs(dx) < fabs(dy)) {
#endif
ptr_left--;
--x_left;
while (floor++ != ptr_left)
blendPixelPtrClip(floor, color, 50, ++x_floor, y_floor);
#if FIXED_POINT
int gradient = (dx << 8) / (dy + 0x100);
int interx = (x1 << 8) + gradient;
#else
double gradient = dx / (dy + 1);
double interx = x1 + gradient;
#endif
for (int y = y1 + 1; y < y2; y++) {
#if FIXED_POINT
if (interx + gradient > ipart(interx) + 0x100) {
#else
if (interx + gradient > ipart(interx) + 1) {
#endif
ptr_right++;
ptr_left--;
++x_right;
--x_left;
}
ptr_left += pitch;
ptr_right += pitch;
y_right += y_pitch_sign;
y_left += y_pitch_sign;
interx += gradient;
switch (fill_m) {
case kFillDisabled:
if (IS_IN_CLIP(x_left, y_left)) *ptr_left = color;
if (IS_IN_CLIP(x_right, y_right)) *ptr_right = color;
break;
case kFillForeground:
case kFillBackground:
colorFillClip<PixelType>(ptr_right + 1, ptr_left, color, x_right+1, y_right, _clippingArea);
blendPixelPtrClip(ptr_right, color, rfpart(interx), x_right, y_right);
blendPixelPtrClip(ptr_left, color, rfpart(interx), x_left, y_left);
break;
case kFillGradient:
colorFillClip<PixelType>(ptr_right, ptr_left, calcGradient(gradient_h++, h), x_right, y_right, _clippingArea);
blendPixelPtrClip(ptr_right, color, rfpart(interx), x_right, y_right);
blendPixelPtrClip(ptr_left, color, rfpart(interx), x_left, y_left);
break;
}
}
return;
}
ptr_left--;
--x_left;
while (floor++ != ptr_left)
blendPixelPtrClip(floor, color, 50, ++x_floor, y_floor);
#if FIXED_POINT
int gradient = (dx / dy) << 8;
int interx = (x1 << 8) + gradient;
#else
double gradient = dx / dy;
double interx = x1 + gradient;
#endif
for (int y = y1 + 1; y < y2; y++) {
ptr_right++;
ptr_left--;
++x_right;
--x_left;
ptr_left += pitch;
ptr_right += pitch;
y_right += y_pitch_sign;
y_left += y_pitch_sign;
interx += gradient;
switch (fill_m) {
case kFillDisabled:
if (IS_IN_CLIP(x_left, y_left)) *ptr_left = color;
if (IS_IN_CLIP(x_right, y_right)) *ptr_right = color;
break;
case kFillForeground:
case kFillBackground:
colorFillClip<PixelType>(ptr_right + 1, ptr_left, color, x_right+1, y_right, _clippingArea);
blendPixelPtrClip(ptr_right, color, rfpart(interx), x_right, y_right);
blendPixelPtrClip(ptr_left, color, rfpart(interx), x_left, y_left);
break;
case kFillGradient:
colorFillClip<PixelType>(ptr_right, ptr_left, calcGradient(gradient_h++, h), x_right, y_right, _clippingArea);
blendPixelPtrClip(ptr_right, color, rfpart(interx), x_right, y_right);
blendPixelPtrClip(ptr_left, color, rfpart(interx), x_left, y_left);
break;
}
}
}
/////////////
/** VERTICAL TRIANGLE DRAWING - FAST VERSION FOR SQUARED TRIANGLES */
template<typename PixelType>
void VectorRendererSpec<PixelType>::

View File

@ -50,14 +50,15 @@ class VectorRendererSpec : public VectorRenderer {
public:
VectorRendererSpec(PixelFormat format);
void drawLine(int x1, int y1, int x2, int y2);
void drawCircle(int x, int y, int r);
void drawSquare(int x, int y, int w, int h);
void drawLine(int x1, int y1, int x2, int y2); //TODO
void drawCircle(int x, int y, int r); //TODO
void drawSquare(int x, int y, int w, int h); //TODO
void drawRoundedSquare(int x, int y, int r, int w, int h);
void drawRoundedSquareClip(int x, int y, int r, int w, int h, int cx, int cy, int cw, int ch);
void drawTriangle(int x, int y, int base, int height, TriangleOrientation orient);
void drawTab(int x, int y, int r, int w, int h);
void drawBeveledSquare(int x, int y, int w, int h, int bevel) {
void drawTriangle(int x, int y, int base, int height, TriangleOrientation orient); //TODO
void drawTriangleClip(int x, int y, int base, int height, TriangleOrientation orient, Common::Rect clipping);
void drawTab(int x, int y, int r, int w, int h); //TODO
void drawBeveledSquare(int x, int y, int w, int h, int bevel) { //TODO
drawBevelSquareAlg(x, y, w, h, bevel, _bevelColor, _fgColor, Base::_fillMode != kFillDisabled);
}
void drawString(const Graphics::Font *font, const Common::String &text,
@ -122,6 +123,7 @@ protected:
* @param alpha Alpha intensity of the pixel (0-255)
*/
inline void blendPixelPtr(PixelType *ptr, PixelType color, uint8 alpha);
inline void blendPixelPtrClip(PixelType *ptr, PixelType color, uint8 alpha, int x, int y);
/**
* Blends a single pixel on the surface in the given pixel pointer, using supplied color
@ -182,6 +184,9 @@ protected:
virtual void drawTriangleVertAlg(int x, int y, int w, int h,
bool inverted, PixelType color, FillMode fill_m);
virtual void drawTriangleVertAlgClip(int x, int y, int w, int h,
bool inverted, PixelType color, FillMode fill_m);
virtual void drawTriangleFast(int x, int y, int size,
bool inverted, PixelType color, FillMode fill_m);

View File

@ -1127,6 +1127,29 @@ void ThemeEngine::drawScrollbar(const Common::Rect &r, int sliderY, int sliderHe
queueDD(scrollState == kScrollbarStateSlider ? kDDScrollbarHandleHover : kDDScrollbarHandleIdle, r2);
}
void ThemeEngine::drawScrollbarClip(const Common::Rect &r, const Common::Rect &clippingRect, int sliderY, int sliderHeight, ScrollbarState scrollState, WidgetStateInfo state) {
if (!ready())
return;
queueDDClip(kDDScrollbarBase, r, clippingRect);
Common::Rect r2 = r;
const int buttonExtra = (r.width() * 120) / 100;
r2.bottom = r2.top + buttonExtra;
queueDDClip(scrollState == kScrollbarStateUp ? kDDScrollbarButtonHover : kDDScrollbarButtonIdle, r2, clippingRect, Graphics::VectorRenderer::kTriangleUp);
r2.translate(0, r.height() - r2.height());
queueDDClip(scrollState == kScrollbarStateDown ? kDDScrollbarButtonHover : kDDScrollbarButtonIdle, r2, clippingRect, Graphics::VectorRenderer::kTriangleDown);
r2 = r;
r2.left += 1;
r2.right -= 1;
r2.top += sliderY;
r2.bottom = r2.top + sliderHeight;
queueDDClip(scrollState == kScrollbarStateSlider ? kDDScrollbarHandleHover : kDDScrollbarHandleIdle, r2, clippingRect);
}
void ThemeEngine::drawDialogBackground(const Common::Rect &r, DialogBackground bgtype, WidgetStateInfo state) {
if (!ready())
return;
@ -1199,7 +1222,7 @@ void ThemeEngine::drawPopUpWidgetClip(const Common::Rect &r, const Common::Rect
else if (state == kStateDisabled)
dd = kDDPopUpDisabled;
queueDDClip(dd, r, clip);
queueDDClip(dd, r, clip);
if (!sel.empty()) {
Common::Rect text(r.left + 3, r.top + 1, r.right - 10, r.bottom);

View File

@ -368,6 +368,8 @@ public:
void drawScrollbar(const Common::Rect &r, int sliderY, int sliderHeight,
ScrollbarState, WidgetStateInfo state = kStateEnabled);
void drawScrollbarClip(const Common::Rect &r, const Common::Rect &clippingRect, int sliderY, int sliderHeight,
ScrollbarState scrollState, WidgetStateInfo state = kStateEnabled);
void drawPopUpWidget(const Common::Rect &r, const Common::String &sel,
int deltax, WidgetStateInfo state = kStateEnabled, Graphics::TextAlign align = Graphics::kTextAlignLeft);

View File

@ -26,6 +26,7 @@
#include "gui/widgets/scrollbar.h"
#include "gui/gui-manager.h"
#include "gui/ThemeEngine.h"
#include "gui/widgets/scrollcontainer.h"
namespace GUI {
@ -202,7 +203,11 @@ void ScrollBarWidget::drawWidget() {
state = ThemeEngine::kScrollbarStateSlider;
}
g_gui.theme()->drawScrollbar(Common::Rect(_x, _y, _x+_w, _y+_h), _sliderPos, _sliderHeight, state, _state);
Common::Rect clipRect = getBossClipRect();
//scrollbar is not a usual child of ScrollContainerWidget, so it gets this special treatment
if (dynamic_cast<ScrollContainerWidget *>(_boss))
clipRect.right += _w;
g_gui.theme()->drawScrollbarClip(Common::Rect(_x, _y, _x+_w, _y+_h), clipRect, _sliderPos, _sliderHeight, state, _state);
}
} // End of namespace GUI