diff options
Diffstat (limited to 'graphics/VectorRendererSpec.cpp')
-rw-r--r-- | graphics/VectorRendererSpec.cpp | 1787 |
1 files changed, 1773 insertions, 14 deletions
diff --git a/graphics/VectorRendererSpec.cpp b/graphics/VectorRendererSpec.cpp index 81a0c04441..fc741f6e77 100644 --- a/graphics/VectorRendererSpec.cpp +++ b/graphics/VectorRendererSpec.cpp @@ -108,6 +108,33 @@ inline frac_t fp_sqroot(uint32 x) { BE_DRAWCIRCLE_BOTTOM(ptr3,ptr4,x,y,px,py); \ } while (0) +#define BE_DRAWCIRCLE_TOP_CLIP(ptr1,ptr2,x,y,px,py,realX1,realY1,realX2,realY2) do { \ + if (IS_IN_CLIP((realX1) + (y), (realY1) - (x))) \ + *(ptr1 + (y) - (px)) = color; \ + if (IS_IN_CLIP((realX1) + (x), (realY1) - (y))) \ + *(ptr1 + (x) - (py)) = color; \ + if (IS_IN_CLIP((realX2) - (x), (realY2) - (y))) \ + *(ptr2 - (x) - (py)) = color; \ + if (IS_IN_CLIP((realX2) - (y), (realY2) - (x))) \ + *(ptr2 - (y) - (px)) = color; \ +} while (0) + +#define BE_DRAWCIRCLE_BOTTOM_CLIP(ptr3,ptr4,x,y,px,py,realX3,realY3,realX4,realY4) do { \ + if (IS_IN_CLIP((realX3) - (y), (realY3) + (x))) \ + *(ptr3 - (y) + (px)) = color; \ + if (IS_IN_CLIP((realX3) - (x), (realY3) + (y))) \ + *(ptr3 - (x) + (py)) = color; \ + if (IS_IN_CLIP((realX4) + (x), (realY4) + (y))) \ + *(ptr4 + (x) + (py)) = color; \ + if (IS_IN_CLIP((realX4) + (y), (realY4) + (x))) \ + *(ptr4 + (y) + (px)) = color; \ +} while (0) + +#define BE_DRAWCIRCLE_CLIP(ptr1,ptr2,ptr3,ptr4,x,y,px,py,realX1,realY1,realX2,realY2,realX3,realY3,realX4,realY4) do { \ + BE_DRAWCIRCLE_TOP_CLIP(ptr1,ptr2,x,y,px,py,realX1,realY1,realX2,realY2); \ + BE_DRAWCIRCLE_BOTTOM_CLIP(ptr3,ptr4,x,y,px,py,realX3,realY3,realX4,realY4); \ +} while (0) + #define BE_DRAWCIRCLE_BCOLOR(ptr1,ptr2,ptr3,ptr4,x,y,px,py) do { \ *(ptr1 + (y) - (px)) = color1; \ *(ptr1 + (x) - (py)) = color1; \ @@ -119,6 +146,25 @@ inline frac_t fp_sqroot(uint32 x) { *(ptr4 + (y) + (px)) = color2; \ } while (0) +#define BE_DRAWCIRCLE_BCOLOR_CLIP(ptr1,ptr2,ptr3,ptr4,x,y,px,py,realX1,realY1,realX2,realY2,realX3,realY3,realX4,realY4) do { \ + if (IS_IN_CLIP((realX1) + (y), (realY1) - (x))) \ + *(ptr1 + (y) - (px)) = color1; \ + if (IS_IN_CLIP((realX1) + (x), (realY1) - (y))) \ + *(ptr1 + (x) - (py)) = color1; \ + if (IS_IN_CLIP((realX2) - (x), (realY2) - (y))) \ + *(ptr2 - (x) - (py)) = color1; \ + if (IS_IN_CLIP((realX2) - (y), (realY2) - (x))) \ + *(ptr2 - (y) - (px)) = color1; \ + if (IS_IN_CLIP((realX3) - (y), (realY3) + (x))) \ + *(ptr3 - (y) + (px)) = color1; \ + if (IS_IN_CLIP((realX3) - (x), (realY3) + (y))) \ + *(ptr3 - (x) + (py)) = color1; \ + if (IS_IN_CLIP((realX4) + (x), (realY4) + (y))) \ + *(ptr4 + (x) + (py)) = color2; \ + if (IS_IN_CLIP((realX4) + (y), (realY4) + (x))) \ + *(ptr4 + (y) + (px)) = color2; \ +} while (0) + #define BE_DRAWCIRCLE_BCOLOR_TR_CW(ptr,x,y,px,py,a) do { \ this->blendPixelPtr(ptr + (y) - (px), color, a); \ } while (0) @@ -127,6 +173,16 @@ inline frac_t fp_sqroot(uint32 x) { this->blendPixelPtr(ptr + (x) - (py), color, a); \ } while (0) +#define BE_DRAWCIRCLE_BCOLOR_TR_CW_CLIP(ptr,x,y,px,py,a,realX,realY) do { \ + if (IS_IN_CLIP((realX) + (y), (realY) - (x))) \ + this->blendPixelPtr(ptr + (y) - (px), color, a); \ +} while (0) + +#define BE_DRAWCIRCLE_BCOLOR_TR_CCW_CLIP(ptr,x,y,px,py,a,realX,realY) do { \ + if (IS_IN_CLIP((realX) + (x), (realY) - (y))) \ + this->blendPixelPtr(ptr + (x) - (py), color, a); \ +} while (0) + #define BE_DRAWCIRCLE_BCOLOR_TL_CW(ptr,x,y,px,py,a) do { \ this->blendPixelPtr(ptr - (x) - (py), color, a); \ } while (0) @@ -135,6 +191,16 @@ inline frac_t fp_sqroot(uint32 x) { this->blendPixelPtr(ptr - (y) - (px), color, a); \ } while (0) +#define BE_DRAWCIRCLE_BCOLOR_TL_CW_CLIP(ptr,x,y,px,py,a,realX,realY) do { \ + if (IS_IN_CLIP((realX) - (x), (realY) - (y))) \ + this->blendPixelPtr(ptr - (x) - (py), color, a); \ +} while (0) + +#define BE_DRAWCIRCLE_BCOLOR_TL_CCW_CLIP(ptr,x,y,px,py,a,realX,realY) do { \ + if (IS_IN_CLIP((realX) - (y), (realY) - (x))) \ + this->blendPixelPtr(ptr - (y) - (px), color, a); \ +} while (0) + #define BE_DRAWCIRCLE_BCOLOR_BL_CW(ptr,x,y,px,py,a) do { \ this->blendPixelPtr(ptr - (y) + (px), color, a); \ } while (0) @@ -143,6 +209,16 @@ inline frac_t fp_sqroot(uint32 x) { this->blendPixelPtr(ptr - (x) + (py), color, a); \ } while (0) +#define BE_DRAWCIRCLE_BCOLOR_BL_CW_CLIP(ptr,x,y,px,py,a,realX,realY) do { \ + if (IS_IN_CLIP((realX) - (y), (realY) + (x))) \ + this->blendPixelPtr(ptr - (y) + (px), color, a); \ +} while (0) + +#define BE_DRAWCIRCLE_BCOLOR_BL_CCW_CLIP(ptr,x,y,px,py,a,realX,realY) do { \ + if (IS_IN_CLIP((realX) - (x), (realY) + (y))) \ + this->blendPixelPtr(ptr - (x) + (py), color, a); \ +} while (0) + #define BE_DRAWCIRCLE_BCOLOR_BR_CW(ptr,x,y,px,py,a) do { \ this->blendPixelPtr(ptr + (x) + (py), color, a); \ } while (0) @@ -151,6 +227,16 @@ inline frac_t fp_sqroot(uint32 x) { this->blendPixelPtr(ptr + (y) + (px), color, a); \ } while (0) +#define BE_DRAWCIRCLE_BCOLOR_BR_CW_CLIP(ptr,x,y,px,py,a,realX,realY) do { \ + if (IS_IN_CLIP((realX) + (x), (realY) + (y))) \ + this->blendPixelPtr(ptr + (x) + (py), color, a); \ +} while (0) + +#define BE_DRAWCIRCLE_BCOLOR_BR_CCW_CLIP(ptr,x,y,px,py,a,realX,realY) do { \ + if (IS_IN_CLIP((realX) + (y), (realY) + (x))) \ + this->blendPixelPtr(ptr + (y) + (px), color, a); \ +} while (0) + #define BE_DRAWCIRCLE_XCOLOR_TOP(ptr1,ptr2,x,y,px,py) do { \ *(ptr1 + (y) - (px)) = color1; \ *(ptr1 + (x) - (py)) = color2; \ @@ -170,6 +256,42 @@ inline frac_t fp_sqroot(uint32 x) { BE_DRAWCIRCLE_XCOLOR_BOTTOM(ptr3,ptr4,x,y,px,py); \ } while (0) +#define IS_IN_CLIP(x,y) (_clippingArea.left <= (x) && (x) < _clippingArea.right \ + && _clippingArea.top <= (y) && (y) < _clippingArea.bottom) + +#define BE_DRAWCIRCLE_XCOLOR_TOP_CLIP(ptr1,ptr2,x,y,px,py,realX1,realY1,realX2,realY2) do { \ + if (IS_IN_CLIP((realX1) + (y), (realY1) - (x))) \ + *(ptr1 + (y) - (px)) = color1; \ +\ + if (IS_IN_CLIP((realX1) + (x), (realY1) - (y))) \ + *(ptr1 + (x) - (py)) = color2; \ +\ + if (IS_IN_CLIP((realX2) - (x), (realY2) - (y))) \ + *(ptr2 - (x) - (py)) = color2; \ +\ + if (IS_IN_CLIP((realX2) - (y), (realY2) - (x))) \ + *(ptr2 - (y) - (px)) = color1; \ +} while (0) + +#define BE_DRAWCIRCLE_XCOLOR_BOTTOM_CLIP(ptr3,ptr4,x,y,px,py,realX3,realY3,realX4,realY4) do { \ + if (IS_IN_CLIP((realX3) - (y), (realY3) + (x))) \ + *(ptr3 - (y) + (px)) = color3; \ +\ + if (IS_IN_CLIP((realX3) - (x), (realY3) + (y))) \ + *(ptr3 - (x) + (py)) = color4; \ +\ + if (IS_IN_CLIP((realX4) + (x), (realY4) + (y))) \ + *(ptr4 + (x) + (py)) = color4; \ +\ + if (IS_IN_CLIP((realX4) + (y), (realY4) + (x))) \ + *(ptr4 + (y) + (px)) = color3; \ +} while (0) + +#define BE_DRAWCIRCLE_XCOLOR_CLIP(ptr1,ptr2,ptr3,ptr4,x,y,px,py,realX1,realY1,realX2,realY2,realX3,realY3,realX4,realY4) do { \ + BE_DRAWCIRCLE_XCOLOR_TOP_CLIP(ptr1,ptr2,x,y,px,py,realX1,realY1,realX2,realY2); \ + BE_DRAWCIRCLE_XCOLOR_BOTTOM_CLIP(ptr3,ptr4,x,y,px,py,realX3,realY3,realX4,realY4); \ +} while (0) + #define BE_RESET() do { \ f = 1 - r; \ @@ -337,6 +459,45 @@ void colorFill(PixelType *first, PixelType *last, PixelType color) { } } +template<typename PixelType> +void colorFillClip(PixelType *first, PixelType *last, PixelType color, int realX, int realY, Common::Rect &clippingArea) { + if (realY < clippingArea.top || realY >= clippingArea.bottom) + return; + + register int count = (last - first); + + if (realX > clippingArea.right || realX + count < clippingArea.left) + return; + + if (realX < clippingArea.left) { + register int diff = (clippingArea.left - realX); + realX += diff; + count -= diff; + } + + if (clippingArea.right <= realX + count) { + register int diff = (realX + count - clippingArea.right); + count -= diff; + } + + if (!count) + return; + + register int n = (count + 7) >> 3; + switch (count % 8) { + case 0: do { + *first++ = color; + case 7: *first++ = color; + case 6: *first++ = color; + case 5: *first++ = color; + case 4: *first++ = color; + case 3: *first++ = color; + case 2: *first++ = color; + case 1: *first++ = color; + } while (--n > 0); + } +} + VectorRenderer *createRenderer(int mode) { #ifdef DISABLE_FANCY_THEMES @@ -376,6 +537,7 @@ VectorRendererSpec(PixelFormat format) : _alphaMask((0xFF >> format.aLoss) << format.aShift) { _bitmapAlphaColor = _format.RGBToColor(255, 0, 255); + _clippingArea = Common::Rect(0, 0, 32767, 32767); } /**************************** @@ -441,13 +603,56 @@ template<typename PixelType> void VectorRendererSpec<PixelType>:: gradientFill(PixelType *ptr, int width, int x, int y) { bool ox = ((y & 1) == 1); - int stripSize; int curGrad = 0; while (_gradIndexes[curGrad + 1] <= y) curGrad++; - stripSize = _gradIndexes[curGrad + 1] - _gradIndexes[curGrad]; + // precalcGradient assures that _gradIndexes entries always differ in + // their value. This assures stripSize is always different from zero. + int stripSize = _gradIndexes[curGrad + 1] - _gradIndexes[curGrad]; + + int grad = (((y - _gradIndexes[curGrad]) % stripSize) << 2) / stripSize; + + // Dithering: + // +--+ +--+ +--+ +--+ + // | | | | | *| | *| + // | | | *| |* | |**| + // +--+ +--+ +--+ +--+ + // 0 1 2 3 + if (grad == 0 || + _gradCache[curGrad] == _gradCache[curGrad + 1] || // no color change + stripSize < 2) { // the stip is small + colorFill<PixelType>(ptr, ptr + width, _gradCache[curGrad]); + } else if (grad == 3 && ox) { + colorFill<PixelType>(ptr, ptr + width, _gradCache[curGrad + 1]); + } else { + for (int j = x; j < x + width; j++, ptr++) { + bool oy = ((j & 1) == 1); + + if ((ox && oy) || + ((grad == 2 || grad == 3) && ox && !oy) || + (grad == 3 && oy)) + *ptr = _gradCache[curGrad + 1]; + else + *ptr = _gradCache[curGrad]; + } + } +} + +template<typename PixelType> +void VectorRendererSpec<PixelType>:: +gradientFillClip(PixelType *ptr, int width, int x, int y, int realX, int realY) { + if (realY < _clippingArea.top || realY >= _clippingArea.bottom) return; + bool ox = ((y & 1) == 1); + int curGrad = 0; + + while (_gradIndexes[curGrad + 1] <= y) + curGrad++; + + // precalcGradient assures that _gradIndexes entries always differ in + // their value. This assures stripSize is always different from zero. + int stripSize = _gradIndexes[curGrad + 1] - _gradIndexes[curGrad]; int grad = (((y - _gradIndexes[curGrad]) % stripSize) << 2) / stripSize; @@ -465,6 +670,7 @@ gradientFill(PixelType *ptr, int width, int x, int y) { colorFill<PixelType>(ptr, ptr + width, _gradCache[curGrad + 1]); } else { for (int j = x; j < x + width; j++, ptr++) { + if (realX + j - x < _clippingArea.left || realX + j - x >= _clippingArea.right) continue; bool oy = ((j & 1) == 1); if ((ox && oy) || @@ -502,6 +708,44 @@ fillSurface() { template<typename PixelType> void VectorRendererSpec<PixelType>:: +fillSurfaceClip(Common::Rect clipping) { + int w = _activeSurface->w; + int h = _activeSurface->h; + if (clipping.isEmpty() || (clipping.left == 0 && clipping.top == 0 && clipping.right == w && clipping.bottom == h)) { + fillSurface(); + return; + } + + byte *ptr = (byte *)_activeSurface->getPixels(); + int pitch = _activeSurface->pitch; + + if (Base::_fillMode == kFillBackground || Base::_fillMode == kFillForeground) { + PixelType color = (Base::_fillMode == kFillBackground ? _bgColor : _fgColor); + byte *ptrLeft = (ptr + _clippingArea.left), *ptrRight = ptr + _clippingArea.right; + for (int i = 0; i < h; i++) { + if (_clippingArea.top <= i && i < _clippingArea.bottom) { + colorFill<PixelType>((PixelType *)ptrLeft, (PixelType *)ptrRight, color); + } + + ptrLeft += pitch; + ptrRight += pitch; + } + + } else if (Base::_fillMode == kFillGradient) { + precalcGradient(h); + + for (int i = 0; i < h; i++) { + if (_clippingArea.top <= i && i < _clippingArea.bottom) { + gradientFill((PixelType *)ptr + _clippingArea.left, _clippingArea.width(), 0, i); + } + + ptr += pitch; + } + } +} + +template<typename PixelType> +void VectorRendererSpec<PixelType>:: copyFrame(OSystem *sys, const Common::Rect &r) { sys->copyRectToOverlay( @@ -553,6 +797,58 @@ blitSubSurface(const Graphics::Surface *source, const Common::Rect &r) { template<typename PixelType> void VectorRendererSpec<PixelType>:: +blitSubSurfaceClip(const Graphics::Surface *source, const Common::Rect &r, const Common::Rect &clipping) { + if (clipping.isEmpty() || clipping.contains(r)) { + blitSubSurface(source, r); + return; + } + + int16 x = r.left; + int16 y = r.top; + + if (r.width() > source->w) + x = x + (r.width() >> 1) - (source->w >> 1); + + if (r.height() > source->h) + y = y + (r.height() >> 1) - (source->h >> 1); + + int w = source->w, h = source->h; + int usedW = w, usedH = h; + int offsetX = 0, offsetY = 0; + + if (x > clipping.right || x + w < clipping.left) return; + if (y > clipping.bottom || y + h < clipping.top) return; + if (x < clipping.left) { + offsetX = clipping.left - x; + usedW -= offsetX; + x = clipping.left; + } + if (y < clipping.top) { + offsetY = clipping.top - y; + usedH -= offsetY; + y = clipping.top; + } + if (usedW > clipping.width()) usedW = clipping.width(); + if (usedH > clipping.height()) usedH = clipping.height(); + + byte *dst_ptr = (byte *)_activeSurface->getBasePtr(x, y); + const byte *src_ptr = (const byte *)source->getBasePtr(offsetX, offsetY); + + const int dst_pitch = _activeSurface->pitch; + const int src_pitch = source->pitch; + + int lines = usedH; + const int sz = usedW * sizeof(PixelType); + + while (lines--) { + memcpy(dst_ptr, src_ptr, sz); + dst_ptr += dst_pitch; + src_ptr += src_pitch; + } +} + +template<typename PixelType> +void VectorRendererSpec<PixelType>:: blitAlphaBitmap(const Graphics::Surface *source, const Common::Rect &r) { int16 x = r.left; int16 y = r.top; @@ -589,6 +885,65 @@ blitAlphaBitmap(const Graphics::Surface *source, const Common::Rect &r) { template<typename PixelType> void VectorRendererSpec<PixelType>:: +blitAlphaBitmapClip(const Graphics::Surface *source, const Common::Rect &r, const Common::Rect &clipping) { + if (clipping.isEmpty() || clipping.contains(r)) { + blitAlphaBitmap(source, r); + return; + } + + int16 x = r.left; + int16 y = r.top; + + if (r.width() > source->w) + x = x + (r.width() >> 1) - (source->w >> 1); + + if (r.height() > source->h) + y = y + (r.height() >> 1) - (source->h >> 1); + + int w = source->w, h = source->h; + int usedW = w, usedH = h; + int offsetX = 0, offsetY = 0; + + if (x > clipping.right || x + w < clipping.left) return; + if (y > clipping.bottom || y + h < clipping.top) return; + if (x < clipping.left) { + offsetX = clipping.left - x; + usedW -= offsetX; + x = clipping.left; + } + if (y < clipping.top) { + offsetY = clipping.top - y; + usedH -= offsetY; + y = clipping.top; + } + if (usedW > clipping.width()) usedW = clipping.width(); + if (usedH > clipping.height()) usedH = clipping.height(); + + PixelType *dst_ptr = (PixelType *)_activeSurface->getBasePtr(x, y); + const PixelType *src_ptr = (const PixelType *)source->getBasePtr(offsetX, offsetY); + + int dst_pitch = _activeSurface->pitch / _activeSurface->format.bytesPerPixel; + int src_pitch = source->pitch / source->format.bytesPerPixel; + + h = usedH; + while (h--) { + w = usedW; + + while (w--) { + if (*src_ptr != _bitmapAlphaColor) + *dst_ptr = *src_ptr; + + dst_ptr++; + src_ptr++; + } + + dst_ptr = dst_ptr - usedW + dst_pitch; + src_ptr = src_ptr - usedW + src_pitch; + } +} + +template<typename PixelType> +void VectorRendererSpec<PixelType>:: applyScreenShading(GUI::ThemeEngine::ShadingStyle shadingStyle) { int pixels = _activeSurface->w * _activeSurface->h; PixelType *ptr = (PixelType *)_activeSurface->getPixels(); @@ -666,6 +1021,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) { int idst = *ptr; // This function is only used for corner pixels in rounded rectangles, so @@ -709,6 +1071,36 @@ darkenFill(PixelType *ptr, PixelType *end) { } } +template<typename PixelType> +inline void VectorRendererSpec<PixelType>:: +darkenFillClip(PixelType *ptr, PixelType *end, int x, int y) { + PixelType mask = (PixelType)((3 << _format.rShift) | (3 << _format.gShift) | (3 << _format.bShift)); + + if (!g_system->hasFeature(OSystem::kFeatureOverlaySupportsAlpha)) { + // !kFeatureOverlaySupportsAlpha (but might have alpha bits) + + while (ptr != end) { + if (IS_IN_CLIP(x, y)) *ptr = ((*ptr & ~mask) >> 2) | _alphaMask; + ++ptr; + ++x; + } + } else { + // kFeatureOverlaySupportsAlpha + // assuming at least 3 alpha bits + + mask |= 3 << _format.aShift; + PixelType addA = (PixelType)(3 << (_format.aShift + 6 - _format.aLoss)); + + while (ptr != end) { + // Darken the color, and increase the alpha + // (0% -> 75%, 100% -> 100%) + if (IS_IN_CLIP(x, y)) *ptr = (PixelType)(((*ptr & ~mask) >> 2) + addA); + ++ptr; + ++x; + } + } +} + /******************************************************************** ******************************************************************** * Primitive shapes drawing - Public API calls - VectorRendererSpec * @@ -773,8 +1165,8 @@ drawLine(int x1, int y1, int x2, int y2) { SWAP(y1, y2); } - int dx = ABS(x2 - x1); - int dy = ABS(y2 - y1); + uint dx = ABS(x2 - x1); + uint dy = ABS(y2 - y1); // this is a point, not a line. stoopid. if (dy == 0 && dx == 0) @@ -803,7 +1195,7 @@ drawLine(int x1, int y1, int x2, int y2) { ptr += pitch; } - } else if (ABS(dx) == ABS(dy)) { // diagonal lines + } else if (dx == dy) { // diagonal lines // these ones also use a fixed pitch increase pitch += (x2 > x1) ? 1 : -1; @@ -817,6 +1209,77 @@ drawLine(int x1, int y1, int x2, int y2) { } } +template<typename PixelType> +void VectorRendererSpec<PixelType>:: +drawLineClip(int x1, int y1, int x2, int y2, Common::Rect clipping) { + x1 = CLIP(x1, 0, (int)Base::_activeSurface->w); + x2 = CLIP(x2, 0, (int)Base::_activeSurface->w); + y1 = CLIP(y1, 0, (int)Base::_activeSurface->h); + y2 = CLIP(y2, 0, (int)Base::_activeSurface->h); + + // we draw from top to bottom + if (y2 < y1) { + SWAP(x1, x2); + SWAP(y1, y2); + } + + uint dx = ABS(x2 - x1); + uint dy = ABS(y2 - y1); + + // this is a point, not a line. stoopid. + if (dy == 0 && dx == 0) + return; + + if (Base::_strokeWidth == 0) + return; + + PixelType *ptr = (PixelType *)_activeSurface->getBasePtr(x1, y1); + int pitch = _activeSurface->pitch / _activeSurface->format.bytesPerPixel; + int st = Base::_strokeWidth >> 1; + + Common::Rect backup = _clippingArea; + _clippingArea = clipping; + bool needsClipping = !_clippingArea.isEmpty() && (!_clippingArea.contains(x1, y1) || !_clippingArea.contains(x2, y2)); + if (!needsClipping) { + drawLine(x1, y1, x2, y2); + _clippingArea = backup; + return; + } + + int ptr_x = x1, ptr_y = y1; + + if (dy == 0) { // horizontal lines + colorFillClip<PixelType>(ptr, ptr + dx + 1, (PixelType)_fgColor, x1, y1, _clippingArea); + + for (int i = 0, p = pitch; i < st; ++i, p += pitch) { + colorFillClip<PixelType>(ptr + p, ptr + dx + 1 + p, (PixelType)_fgColor, x1, y1 + p/pitch, _clippingArea); + colorFillClip<PixelType>(ptr - p, ptr + dx + 1 - p, (PixelType)_fgColor, x1, y1 - p/pitch, _clippingArea); + } + + } else if (dx == 0) { // vertical lines + // these ones use a static pitch increase. + while (y1++ <= y2) { + colorFillClip<PixelType>(ptr - st, ptr + st, (PixelType)_fgColor, x1 - st, ptr_y, _clippingArea); + ptr += pitch; + ++ptr_y; + } + + } else if (dx == dy) { // diagonal lines + // these ones also use a fixed pitch increase + pitch += (x2 > x1) ? 1 : -1; + + while (dy--) { + colorFillClip<PixelType>(ptr - st, ptr + st, (PixelType)_fgColor, ptr_x - st, ptr_y, _clippingArea); + ptr += pitch; + ++ptr_y; + if (x2 > x1) ++ptr_x; else --ptr_x; + } + + } else { // generic lines, use the standard algorithm... + drawLineAlgClip(x1, y1, x2, y2, dx, dy, (PixelType)_fgColor); + } +} + /** CIRCLES **/ template<typename PixelType> void VectorRendererSpec<PixelType>:: @@ -856,6 +1319,70 @@ drawCircle(int x, int y, int r) { } } +template<typename PixelType> +void VectorRendererSpec<PixelType>:: +drawCircleClip(int x, int y, int r, Common::Rect clipping) { + if (x + r > Base::_activeSurface->w || y + r > Base::_activeSurface->h || + x - r < 0 || y - r < 0 || x == 0 || y == 0 || r <= 0) + return; + + Common::Rect backup = _clippingArea; + _clippingArea = clipping; + bool useClippingVersions = !(_clippingArea.isEmpty() || _clippingArea.contains(Common::Rect(x - r, y - r, x + r, y + r))); + + if (Base::_fillMode != kFillDisabled && Base::_shadowOffset + && x + r + Base::_shadowOffset < Base::_activeSurface->w + && y + r + Base::_shadowOffset < Base::_activeSurface->h) { + if (useClippingVersions) + drawCircleAlgClip(x + Base::_shadowOffset + 1, y + Base::_shadowOffset + 1, r, 0, kFillForeground); + else + drawCircleAlg(x + Base::_shadowOffset + 1, y + Base::_shadowOffset + 1, r, 0, kFillForeground); + } + + switch (Base::_fillMode) { + case kFillDisabled: + if (Base::_strokeWidth) { + if (useClippingVersions) + drawCircleAlgClip(x, y, r, _fgColor, kFillDisabled); + else + drawCircleAlg(x, y, r, _fgColor, kFillDisabled); + } + break; + + case kFillForeground: + if (useClippingVersions) + drawCircleAlgClip(x, y, r, _fgColor, kFillForeground); + else + drawCircleAlg(x, y, r, _fgColor, kFillForeground); + break; + + case kFillBackground: + if (Base::_strokeWidth > 1) { + if (useClippingVersions) { + drawCircleAlgClip(x, y, r, _fgColor, kFillForeground); + drawCircleAlgClip(x, y, r - Base::_strokeWidth, _bgColor, kFillBackground); + } else { + drawCircleAlg(x, y, r, _fgColor, kFillForeground); + drawCircleAlg(x, y, r - Base::_strokeWidth, _bgColor, kFillBackground); + } + } else { + if (useClippingVersions) { + drawCircleAlgClip(x, y, r, _bgColor, kFillBackground); + drawCircleAlgClip(x, y, r, _fgColor, kFillDisabled); + } else { + drawCircleAlg(x, y, r, _bgColor, kFillBackground); + drawCircleAlg(x, y, r, _fgColor, kFillDisabled); + } + } + break; + + case kFillGradient: + break; + } + + _clippingArea = backup; +} + /** SQUARES **/ template<typename PixelType> void VectorRendererSpec<PixelType>:: @@ -893,6 +1420,67 @@ drawSquare(int x, int y, int w, int h) { } } +template<typename PixelType> +void VectorRendererSpec<PixelType>:: +drawSquareClip(int x, int y, int w, int h, Common::Rect clipping) { + if (x + w > Base::_activeSurface->w || y + h > Base::_activeSurface->h || + w <= 0 || h <= 0 || x < 0 || y < 0) + return; + + Common::Rect backup = _clippingArea; + _clippingArea = clipping; + bool useClippingVersions = !(_clippingArea.isEmpty() || _clippingArea.contains(Common::Rect(x, y, x + w, y + h))); + + if (Base::_fillMode != kFillDisabled && Base::_shadowOffset + && x + w + Base::_shadowOffset < Base::_activeSurface->w + && y + h + Base::_shadowOffset < Base::_activeSurface->h) { + if (useClippingVersions) + drawSquareShadowClip(x, y, w, h, Base::_shadowOffset); + else + drawSquareShadow(x, y, w, h, Base::_shadowOffset); + } + + switch (Base::_fillMode) { + case kFillDisabled: + if (Base::_strokeWidth) { + if (useClippingVersions) + drawSquareAlgClip(x, y, w, h, _fgColor, kFillDisabled); + else + drawSquareAlg(x, y, w, h, _fgColor, kFillDisabled); + } + break; + + case kFillForeground: + if (useClippingVersions) + drawSquareAlgClip(x, y, w, h, _fgColor, kFillForeground); + else + drawSquareAlg(x, y, w, h, _fgColor, kFillForeground); + break; + + case kFillBackground: + if (useClippingVersions) { + drawSquareAlgClip(x, y, w, h, _bgColor, kFillBackground); + drawSquareAlgClip(x, y, w, h, _fgColor, kFillDisabled); + } else { + drawSquareAlg(x, y, w, h, _bgColor, kFillBackground); + drawSquareAlg(x, y, w, h, _fgColor, kFillDisabled); + } + break; + + case kFillGradient: + VectorRendererSpec::drawSquareAlg(x, y, w, h, 0, kFillGradient); + if (Base::_strokeWidth) { + if (useClippingVersions) + drawSquareAlgClip(x, y, w, h, _fgColor, kFillDisabled); + else + drawSquareAlg(x, y, w, h, _fgColor, kFillDisabled); + } + break; + } + + _clippingArea = backup; +} + /** ROUNDED SQUARES **/ template<typename PixelType> void VectorRendererSpec<PixelType>:: @@ -919,6 +1507,43 @@ drawRoundedSquare(int x, int y, int r, int w, int h) { template<typename PixelType> void VectorRendererSpec<PixelType>:: +drawRoundedSquareClip(int x, int y, int r, int w, int h, Common::Rect clipping) { + if (x + w > Base::_activeSurface->w || y + h > Base::_activeSurface->h || + w <= 0 || h <= 0 || x < 0 || y < 0 || r <= 0) + return; + + if ((r * 2) > w || (r * 2) > h) + r = MIN(w / 2, h / 2); + + if (r <= 0) + return; + + Common::Rect backup = _clippingArea; + _clippingArea = clipping; + bool useOriginal = (_clippingArea.isEmpty() || _clippingArea.contains(Common::Rect(x, y, x + w, y + h))); + + if (Base::_fillMode != kFillDisabled && Base::_shadowOffset + && x + w + Base::_shadowOffset + 1 < Base::_activeSurface->w + && y + h + Base::_shadowOffset + 1 < Base::_activeSurface->h + && h > (Base::_shadowOffset + 1) * 2) { + if (useOriginal) { + drawRoundedSquareShadow(x, y, r, w, h, Base::_shadowOffset); + } else { + drawRoundedSquareShadowClip(x, y, r, w, h, Base::_shadowOffset); + } + } + + if (useOriginal) { + drawRoundedSquareAlg(x, y, r, w, h, _fgColor, Base::_fillMode); + } else { + drawRoundedSquareAlgClip(x, y, r, w, h, _fgColor, Base::_fillMode); + } + + _clippingArea = backup; +} + +template<typename PixelType> +void VectorRendererSpec<PixelType>:: drawTab(int x, int y, int r, int w, int h) { if (x + w > Base::_activeSurface->w || y + h > Base::_activeSurface->h || w <= 0 || h <= 0 || x < 0 || y < 0 || r > w || r > h) @@ -955,6 +1580,66 @@ drawTab(int x, int y, int r, int w, int h) { template<typename PixelType> void VectorRendererSpec<PixelType>:: +drawTabClip(int x, int y, int r, int w, int h, Common::Rect clipping) { + if (x + w > Base::_activeSurface->w || y + h > Base::_activeSurface->h || + w <= 0 || h <= 0 || x < 0 || y < 0 || r > w || r > h) + return; + + Common::Rect backup = _clippingArea; + _clippingArea = clipping; + bool useClippingVersions = !(_clippingArea.isEmpty() || _clippingArea.contains(Common::Rect(x, y, x + w, y + h))); + + if (r == 0 && Base::_bevel > 0) { + if (useClippingVersions) + drawBevelTabAlgClip(x, y, w, h, Base::_bevel, _bevelColor, _fgColor, (Base::_dynamicData >> 16), (Base::_dynamicData & 0xFFFF)); + else + drawBevelTabAlg(x, y, w, h, Base::_bevel, _bevelColor, _fgColor, (Base::_dynamicData >> 16), (Base::_dynamicData & 0xFFFF)); + _clippingArea = backup; + return; + } + + if (r == 0) { + _clippingArea = backup; + return; + } + + switch (Base::_fillMode) { + case kFillDisabled: + // FIXME: Implement this + _clippingArea = backup; + return; + + case kFillGradient: + case kFillBackground: + // FIXME: This is broken for the AA renderer. + // See the rounded rect alg for how to fix it. (The border should + // be drawn before the interior, both inside drawTabAlg.) + if (useClippingVersions) { + drawTabShadowClip(x, y, w - 2, h, r); + drawTabAlgClip(x, y, w - 2, h, r, _bgColor, Base::_fillMode); + if (Base::_strokeWidth) + drawTabAlgClip(x, y, w, h, r, _fgColor, kFillDisabled, (Base::_dynamicData >> 16), (Base::_dynamicData & 0xFFFF)); + } else { + drawTabShadow(x, y, w - 2, h, r); + drawTabAlg(x, y, w - 2, h, r, _bgColor, Base::_fillMode); + if (Base::_strokeWidth) + drawTabAlg(x, y, w, h, r, _fgColor, kFillDisabled, (Base::_dynamicData >> 16), (Base::_dynamicData & 0xFFFF)); + } + break; + + case kFillForeground: + if (useClippingVersions) + drawTabAlgClip(x, y, w, h, r, _fgColor, Base::_fillMode); + else + drawTabAlg(x, y, w, h, r, _fgColor, Base::_fillMode); + break; + } + + _clippingArea = backup; +} + +template<typename PixelType> +void VectorRendererSpec<PixelType>:: drawTriangle(int x, int y, int w, int h, TriangleOrientation orient) { if (x + w > Base::_activeSurface->w || y + h > Base::_activeSurface->h) @@ -1021,8 +1706,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; +} /******************************************************************** @@ -1034,6 +1799,11 @@ drawTriangle(int x, int y, int w, int h, TriangleOrientation orient) { template<typename PixelType> void VectorRendererSpec<PixelType>:: drawTabAlg(int x1, int y1, int w, int h, int r, PixelType color, VectorRenderer::FillMode fill_m, int baseLeft, int baseRight) { + // Don't draw anything for empty rects. + if (w <= 0 || h <= 0) { + return; + } + int f, ddF_x, ddF_y; int x, y, px, py; int pitch = _activeSurface->pitch / _activeSurface->format.bytesPerPixel; @@ -1128,6 +1898,120 @@ drawTabAlg(int x1, int y1, int w, int h, int r, PixelType color, VectorRenderer: } } +template<typename PixelType> +void VectorRendererSpec<PixelType>:: +drawTabAlgClip(int x1, int y1, int w, int h, int r, PixelType color, VectorRenderer::FillMode fill_m, int baseLeft, int baseRight) { + // Don't draw anything for empty rects. + if (w <= 0 || h <= 0) { + return; + } + + int f, ddF_x, ddF_y; + int x, y, px, py; + int pitch = _activeSurface->pitch / _activeSurface->format.bytesPerPixel; + int sw = 0, sp = 0, hp = 0; + + PixelType *ptr_tl = (PixelType *)Base::_activeSurface->getBasePtr(x1 + r, y1 + r); + PixelType *ptr_tr = (PixelType *)Base::_activeSurface->getBasePtr(x1 + w - r, y1 + r); + PixelType *ptr_fill = (PixelType *)Base::_activeSurface->getBasePtr(x1, y1); + int tl_x = x1 + r, tl_y = y1 + r; + int tr_x = x1 + w - r, tr_y = y1 + r; + int fill_x = x1, fill_y = y1; + + int real_radius = r; + int short_h = h - r + 2; + int long_h = h; + + if (fill_m == kFillDisabled) { + while (sw++ < Base::_strokeWidth) { + colorFillClip<PixelType>(ptr_fill + sp + r, ptr_fill + w + 1 + sp - r, color, fill_x + r, fill_y + sp/pitch, _clippingArea); + colorFillClip<PixelType>(ptr_fill + hp - sp + r, ptr_fill + w + hp + 1 - sp - r, color, fill_x + r, fill_y + hp / pitch - sp / pitch, _clippingArea); + sp += pitch; + + BE_RESET(); + r--; + + while (x++ < y) { + BE_ALGORITHM(); + BE_DRAWCIRCLE_TOP_CLIP(ptr_tr, ptr_tl, x, y, px, py, tr_x, tr_y, tl_x, tl_y); + + if (Base::_strokeWidth > 1) + BE_DRAWCIRCLE_TOP_CLIP(ptr_tr, ptr_tl, x, y, px - pitch, py, tr_x, tr_y, tl_x, tl_y); + } + } + + ptr_fill += pitch * real_radius; + fill_y += real_radius; + while (short_h--) { + colorFillClip<PixelType>(ptr_fill, ptr_fill + Base::_strokeWidth, color, fill_x, fill_y, _clippingArea); + colorFillClip<PixelType>(ptr_fill + w - Base::_strokeWidth + 1, ptr_fill + w + 1, color, fill_x + w - Base::_strokeWidth + 1, fill_y, _clippingArea); + ptr_fill += pitch; + ++fill_y; + } + + if (baseLeft) { + sw = 0; + ptr_fill = (PixelType *)Base::_activeSurface->getBasePtr(x1, y1 + h + 1); + fill_x = x1; + fill_y = y1 + h + 1; + while (sw++ < Base::_strokeWidth) { + colorFillClip<PixelType>(ptr_fill - baseLeft, ptr_fill, color, fill_x - baseLeft, fill_y, _clippingArea); + ptr_fill += pitch; + ++fill_y; + } + } + + if (baseRight) { + sw = 0; + ptr_fill = (PixelType *)Base::_activeSurface->getBasePtr(x1 + w, y1 + h + 1); + fill_x = x1 + w; + fill_y = y1 + h + 1; + while (sw++ < Base::_strokeWidth) { + colorFillClip<PixelType>(ptr_fill, ptr_fill + baseRight, color, fill_x, fill_y, _clippingArea); + ptr_fill += pitch; + ++fill_y; + } + } + } else { + BE_RESET(); + + precalcGradient(long_h); + + PixelType color1, color2; + color1 = color2 = color; + + while (x++ < y) { + BE_ALGORITHM(); + + if (fill_m == kFillGradient) { + color1 = calcGradient(real_radius - x, long_h); + color2 = calcGradient(real_radius - y, long_h); + + gradientFillClip(ptr_tl - x - py, w - 2 * r + 2 * x, x1 + r - x - y, real_radius - y, tl_x - x, tl_y - y); + gradientFillClip(ptr_tl - y - px, w - 2 * r + 2 * y, x1 + r - y - x, real_radius - x, tl_x - y, tl_y - x); + + BE_DRAWCIRCLE_XCOLOR_TOP_CLIP(ptr_tr, ptr_tl, x, y, px, py, tr_x, tr_y, tl_x, tl_y); + } else { + colorFillClip<PixelType>(ptr_tl - x - py, ptr_tr + x - py, color, tl_x - x, tl_y - y, _clippingArea); + colorFillClip<PixelType>(ptr_tl - y - px, ptr_tr + y - px, color, tl_x - y, tl_y - x, _clippingArea); + + BE_DRAWCIRCLE_TOP_CLIP(ptr_tr, ptr_tl, x, y, px, py, tr_x, tr_y, tl_x, tl_y); + } + } + + ptr_fill += pitch * r; + fill_y += r; + while (short_h--) { + if (fill_m == kFillGradient) { + gradientFillClip(ptr_fill, w + 1, x1, real_radius++, fill_x, fill_y); + } else { + colorFillClip<PixelType>(ptr_fill, ptr_fill + w + 1, color, fill_x, fill_y, _clippingArea); + } + ptr_fill += pitch; + ++fill_y; + } + } +} template<typename PixelType> void VectorRendererSpec<PixelType>:: @@ -1190,6 +2074,72 @@ drawTabShadow(int x1, int y1, int w, int h, int r) { } } +template<typename PixelType> +void VectorRendererSpec<PixelType>:: +drawTabShadowClip(int x1, int y1, int w, int h, int r) { + int offset = 3; + int pitch = _activeSurface->pitch / _activeSurface->format.bytesPerPixel; + + // "Harder" shadows when having lower BPP, since we will have artifacts (greenish tint on the modern theme) + uint8 expFactor = 3; + uint16 alpha = (_activeSurface->format.bytesPerPixel > 2) ? 4 : 8; + + int xstart = x1; + int ystart = y1; + int width = w; + int height = h + offset + 1; + + for (int i = offset; i >= 0; i--) { + int f, ddF_x, ddF_y; + int x, y, px, py; + + PixelType *ptr_tl = (PixelType *)Base::_activeSurface->getBasePtr(xstart + r, ystart + r); + PixelType *ptr_tr = (PixelType *)Base::_activeSurface->getBasePtr(xstart + width - r, ystart + r); + PixelType *ptr_fill = (PixelType *)Base::_activeSurface->getBasePtr(xstart, ystart); + + int tl_x = xstart + r, tl_y = ystart + r; + int fill_x = xstart, fill_y = ystart; + + int short_h = height - (2 * r) + 2; + PixelType color = _format.RGBToColor(0, 0, 0); + + BE_RESET(); + + // HACK: As we are drawing circles exploting 8-axis symmetry, + // there are 4 pixels on each circle which are drawn twice. + // this is ok on filled circles, but when blending on surfaces, + // we cannot let it blend twice. awful. + uint32 hb = 0; + + while (x++ < y) { + BE_ALGORITHM(); + + if (((1 << x) & hb) == 0) { + blendFillClip(ptr_tl - y - px, ptr_tr + y - px, color, (uint8)alpha, tl_x - y, tl_y - x); + hb |= (1 << x); + } + + if (((1 << y) & hb) == 0) { + blendFillClip(ptr_tl - x - py, ptr_tr + x - py, color, (uint8)alpha, tl_x - x, tl_y - y); + hb |= (1 << y); + } + } + + ptr_fill += pitch * r; + fill_y += r; + while (short_h--) { + blendFillClip(ptr_fill, ptr_fill + width + 1, color, (uint8)alpha, fill_x, fill_y); + ptr_fill += pitch; + ++fill_y; + } + + // Move shadow one pixel upward each iteration + xstart += 1; + // Multiply with expfactor + alpha = (alpha * (expFactor << 8)) >> 9; + } +} + /** BEVELED TABS FOR CLASSIC THEME **/ template<typename PixelType> void VectorRendererSpec<PixelType>:: @@ -1234,10 +2184,66 @@ drawBevelTabAlg(int x, int y, int w, int h, int bevel, PixelType top_color, Pixe } } +template<typename PixelType> +void VectorRendererSpec<PixelType>:: +drawBevelTabAlgClip(int x, int y, int w, int h, int bevel, PixelType top_color, PixelType bottom_color, int baseLeft, int baseRight) { + int pitch = _activeSurface->pitch / _activeSurface->format.bytesPerPixel; + int i, j; + + PixelType *ptr_left = (PixelType *)_activeSurface->getBasePtr(x, y); + int ptr_x = x, ptr_y = y; + + i = bevel; + while (i--) { + colorFillClip<PixelType>(ptr_left, ptr_left + w, top_color, ptr_x, ptr_y, _clippingArea); + ptr_left += pitch; + ++ptr_y; + } + + if (baseLeft > 0) { + i = h - bevel; + ptr_left = (PixelType *)_activeSurface->getBasePtr(x, y); + ptr_x = x; ptr_y = y; + while (i--) { + colorFillClip<PixelType>(ptr_left, ptr_left + bevel, top_color, ptr_x, ptr_y, _clippingArea); + ptr_left += pitch; + ++ptr_y; + } + } + + i = h - bevel; + j = bevel - 1; + ptr_left = (PixelType *)_activeSurface->getBasePtr(x + w - bevel, y); + ptr_x = x + w - bevel; ptr_y = y; + while (i--) { + colorFillClip<PixelType>(ptr_left + j, ptr_left + bevel, bottom_color, ptr_x + j, ptr_y, _clippingArea); + if (j > 0) j--; + ptr_left += pitch; + ++ptr_y; + } + + i = bevel; + ptr_left = (PixelType *)_activeSurface->getBasePtr(x + w - bevel, y + h - bevel); + ptr_x = x + w - bevel; ptr_y = y + h - bevel; + while (i--) { + colorFillClip<PixelType>(ptr_left, ptr_left + baseRight + bevel, bottom_color, ptr_x, ptr_y, _clippingArea); + + if (baseLeft) + colorFillClip<PixelType>(ptr_left - w - baseLeft + bevel, ptr_left - w + bevel + bevel, top_color, ptr_x - w - baseLeft + bevel, ptr_y, _clippingArea); + ptr_left += pitch; + ++ptr_y; + } +} + /** SQUARE ALGORITHM **/ template<typename PixelType> void VectorRendererSpec<PixelType>:: drawSquareAlg(int x, int y, int w, int h, PixelType color, VectorRenderer::FillMode fill_m) { + // Do not draw anything for empty rects. + if (w <= 0 || h <= 0) { + return; + } + PixelType *ptr = (PixelType *)_activeSurface->getBasePtr(x, y); int pitch = _activeSurface->pitch / _activeSurface->format.bytesPerPixel; int max_h = h; @@ -1267,6 +2273,46 @@ drawSquareAlg(int x, int y, int w, int h, PixelType color, VectorRenderer::FillM } } +template<typename PixelType> +void VectorRendererSpec<PixelType>:: +drawSquareAlgClip(int x, int y, int w, int h, PixelType color, VectorRenderer::FillMode fill_m) { + // Do not draw anything for empty rects. + if (w <= 0 || h <= 0) { + return; + } + + PixelType *ptr = (PixelType *)_activeSurface->getBasePtr(x, y); + int pitch = _activeSurface->pitch / _activeSurface->format.bytesPerPixel; + int max_h = h; + int ptr_y = y; + + if (fill_m != kFillDisabled) { + while (h--) { + if (fill_m == kFillGradient) + color = calcGradient(max_h - h, max_h); + + colorFillClip<PixelType>(ptr, ptr + w, color, x, ptr_y, _clippingArea); + ptr += pitch; + ++ptr_y; + } + } else { + int sw = Base::_strokeWidth, sp = 0, hp = pitch * (h - 1); + + while (sw--) { + colorFillClip<PixelType>(ptr + sp, ptr + w + sp, color, x, ptr_y + sp/pitch, _clippingArea); + colorFillClip<PixelType>(ptr + hp - sp, ptr + w + hp - sp, color, x, ptr_y + h - sp/pitch, _clippingArea); + sp += pitch; + } + + while (h--) { + colorFillClip<PixelType>(ptr, ptr + Base::_strokeWidth, color, x, ptr_y, _clippingArea); + colorFillClip<PixelType>(ptr + w - Base::_strokeWidth, ptr + w, color, x + w - Base::_strokeWidth, ptr_y, _clippingArea); + ptr += pitch; + ptr_y += 1; + } + } +} + /** SQUARE ALGORITHM **/ template<typename PixelType> void VectorRendererSpec<PixelType>:: @@ -1323,10 +2369,76 @@ drawBevelSquareAlg(int x, int y, int w, int h, int bevel, PixelType top_color, P } } +template<typename PixelType> +void VectorRendererSpec<PixelType>:: +drawBevelSquareAlgClip(int x, int y, int w, int h, int bevel, PixelType top_color, PixelType bottom_color, bool fill) { + int pitch = _activeSurface->pitch / _activeSurface->format.bytesPerPixel; + int i, j; + PixelType *ptr_left; + int ptr_x, ptr_y; + + // Fill Background + ptr_left = (PixelType *)_activeSurface->getBasePtr(x, y); + ptr_x = x; ptr_y = y; + i = h; + if (fill) { + assert((_bgColor & ~_alphaMask) == 0); // only support black + while (i--) { + darkenFillClip(ptr_left, ptr_left + w, ptr_x, ptr_y); + ptr_left += pitch; + ++ptr_y; + } + } + + x = MAX(x - bevel, 0); + y = MAX(y - bevel, 0); + + w = MIN(w + (bevel * 2), (int)_activeSurface->w); + h = MIN(h + (bevel * 2), (int)_activeSurface->h); + + ptr_left = (PixelType *)_activeSurface->getBasePtr(x, y); + ptr_x = x; ptr_y = y; + i = bevel; + while (i--) { + colorFillClip<PixelType>(ptr_left, ptr_left + w, top_color, ptr_x, ptr_y, _clippingArea); + ptr_left += pitch; + ++ptr_y; + } + + ptr_left = (PixelType *)_activeSurface->getBasePtr(x, y + bevel); + ptr_x = x; ptr_y = y + bevel; + i = h - bevel; + while (i--) { + colorFillClip<PixelType>(ptr_left, ptr_left + bevel, top_color, ptr_x, ptr_y, _clippingArea); + ptr_left += pitch; + ++ptr_y; + } + + ptr_left = (PixelType *)_activeSurface->getBasePtr(x, y + h - bevel); + ptr_x = x; ptr_y = y + h - bevel; + i = bevel; + while (i--) { + colorFillClip<PixelType>(ptr_left + i, ptr_left + w, bottom_color, ptr_x + i, ptr_y, _clippingArea); + ptr_left += pitch; + ++ptr_y; + } + + ptr_left = (PixelType *)_activeSurface->getBasePtr(x + w - bevel, y); + ptr_x = x + w - bevel; ptr_y = y; + i = h - bevel; + j = bevel - 1; + while (i--) { + colorFillClip<PixelType>(ptr_left + j, ptr_left + bevel, bottom_color, ptr_x + j, ptr_y, _clippingArea); + if (j > 0) j--; + ptr_left += pitch; + ++ptr_y; + } +} + /** GENERIC LINE ALGORITHM **/ template<typename PixelType> void VectorRendererSpec<PixelType>:: -drawLineAlg(int x1, int y1, int x2, int y2, int dx, int dy, PixelType color) { +drawLineAlg(int x1, int y1, int x2, int y2, uint dx, uint dy, PixelType color) { PixelType *ptr = (PixelType *)_activeSurface->getBasePtr(x1, y1); int pitch = _activeSurface->pitch / _activeSurface->format.bytesPerPixel; int xdir = (x2 > x1) ? 1 : -1; @@ -1371,6 +2483,59 @@ drawLineAlg(int x1, int y1, int x2, int y2, int dx, int dy, PixelType color) { *ptr = (PixelType)color; } +template<typename PixelType> +void VectorRendererSpec<PixelType>:: +drawLineAlgClip(int x1, int y1, int x2, int y2, uint dx, uint dy, PixelType color) { + PixelType *ptr = (PixelType *)_activeSurface->getBasePtr(x1, y1); + int pitch = _activeSurface->pitch / _activeSurface->format.bytesPerPixel; + int xdir = (x2 > x1) ? 1 : -1; + int ptr_x = x1, ptr_y = y1; + + if (IS_IN_CLIP(ptr_x, ptr_y)) *ptr = (PixelType)color; + + if (dx > dy) { + int ddy = dy * 2; + int dysub = ddy - (dx * 2); + int error_term = ddy - dx; + + while (dx--) { + if (error_term >= 0) { + ptr += pitch; + ++ptr_y; + error_term += dysub; + } else { + error_term += ddy; + } + + ptr += xdir; + ptr_x += xdir; + if (IS_IN_CLIP(ptr_x, ptr_y)) *ptr = (PixelType)color; + } + } else { + int ddx = dx * 2; + int dxsub = ddx - (dy * 2); + int error_term = ddx - dy; + + while (dy--) { + if (error_term >= 0) { + ptr += xdir; + ptr_x += xdir; + error_term += dxsub; + } else { + error_term += ddx; + } + + ptr += pitch; + ++ptr_y; + if (IS_IN_CLIP(ptr_x, ptr_y)) *ptr = (PixelType)color; + } + } + + ptr = (PixelType *)_activeSurface->getBasePtr(x2, y2); + ptr_x = x2; ptr_y = y2; + if (IS_IN_CLIP(ptr_x, ptr_y)) *ptr = (PixelType)color; +} + /** VERTICAL TRIANGLE DRAWING ALGORITHM **/ /** FIXED POINT ARITHMETIC @@ -1393,6 +2558,12 @@ drawLineAlg(int x1, int y1, int x2, int y2, int dx, int dy, PixelType color) { template<typename PixelType> void VectorRendererSpec<PixelType>:: drawTriangleVertAlg(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; if (!inverted) { @@ -1422,6 +2593,9 @@ drawTriangleVertAlg(int x1, int y1, int w, int h, bool inverted, PixelType color blendPixelPtr(floor, color, 50); #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 @@ -1560,10 +2734,221 @@ 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>:: drawTriangleFast(int x1, int y1, int size, bool inverted, PixelType color, VectorRenderer::FillMode fill_m) { + // Do not draw anything for empty rects. + if (size <= 0) { + return; + } + int pitch = _activeSurface->pitch / _activeSurface->format.bytesPerPixel; if (!inverted) { @@ -1657,6 +3042,9 @@ drawBorderRoundedSquareAlg(int x1, int y1, int r, int w, int h, PixelType color, while (x++ < (y - 2)) { BE_ALGORITHM(); + if (x < _clippingArea.left || x > _clippingArea.right) continue; + if (y < _clippingArea.top || y > _clippingArea.bottom) continue; + BE_DRAWCIRCLE_BCOLOR_TR_CW(ptr_tr, x, y, px, py, (uint8)(alpha_r + (alphaStep_tr * x))); BE_DRAWCIRCLE_BCOLOR_BR_CW(ptr_br, x, y, px, py, (uint8)(alpha_b + (alphaStep_br * x))); BE_DRAWCIRCLE_BCOLOR_BL_CW(ptr_bl, x, y, px, py, (uint8)(alpha_l + (alphaStep_bl * x))); @@ -1684,7 +3072,80 @@ drawBorderRoundedSquareAlg(int x1, int y1, int r, int w, int h, PixelType color, template<typename PixelType> void VectorRendererSpec<PixelType>:: +drawBorderRoundedSquareAlgClip(int x1, int y1, int r, int w, int h, PixelType color, VectorRenderer::FillMode fill_m, uint8 alpha_t, uint8 alpha_r, uint8 alpha_b, uint8 alpha_l) { + int f, ddF_x, ddF_y; + int x, y, px, py; + int pitch = _activeSurface->pitch / _activeSurface->format.bytesPerPixel; + int sw = 0, sp = 0, hp = h * pitch; + + PixelType *ptr_tl = (PixelType *)Base::_activeSurface->getBasePtr(x1 + r, y1 + r); + PixelType *ptr_tr = (PixelType *)Base::_activeSurface->getBasePtr(x1 + w - r, y1 + r); + PixelType *ptr_bl = (PixelType *)Base::_activeSurface->getBasePtr(x1 + r, y1 + h - r); + PixelType *ptr_br = (PixelType *)Base::_activeSurface->getBasePtr(x1 + w - r, y1 + h - r); + PixelType *ptr_fill = (PixelType *)Base::_activeSurface->getBasePtr(x1, y1); + + int real_radius = r; + int short_h = h - (2 * r) + 2; + + PixelType color1 = color; + PixelType color2 = color; + + while (sw++ < Base::_strokeWidth) { + blendFillClip(ptr_fill + sp + r, ptr_fill + w + 1 + sp - r, color1, alpha_t, + x1 + r, y1 + sp/pitch); // top + blendFillClip(ptr_fill + hp - sp + r, ptr_fill + w + hp + 1 - sp - r, color2, alpha_b, + x1 + r, y1 + (hp - sp)/ pitch); // bottom + sp += pitch; + + BE_RESET(); + r--; + + int alphaStep_tr = ((alpha_t - alpha_r) / (y + 1)); + int alphaStep_br = ((alpha_r - alpha_b) / (y + 1)); + int alphaStep_bl = ((alpha_b - alpha_l) / (y + 1)); + int alphaStep_tl = ((alpha_l - alpha_t) / (y + 1)); + + // Avoid blending the last pixels twice, since we have an alpha + while (x++ < (y - 2)) { + BE_ALGORITHM(); + + BE_DRAWCIRCLE_BCOLOR_TR_CW_CLIP(ptr_tr, x, y, px, py, (uint8)(alpha_r + (alphaStep_tr * x)), x1 + w - r, y1 + r); + BE_DRAWCIRCLE_BCOLOR_BR_CW_CLIP(ptr_br, x, y, px, py, (uint8)(alpha_b + (alphaStep_br * x)), x1 + w - r, y1 + h - r); + BE_DRAWCIRCLE_BCOLOR_BL_CW_CLIP(ptr_bl, x, y, px, py, (uint8)(alpha_l + (alphaStep_bl * x)), x1 + r, y1 + h - r); + BE_DRAWCIRCLE_BCOLOR_TL_CW_CLIP(ptr_tl, x, y, px, py, (uint8)(alpha_t + (alphaStep_tl * x)), x1 + r, y1 + r); + + BE_DRAWCIRCLE_BCOLOR_TR_CCW_CLIP(ptr_tr, x, y, px, py, (uint8)(alpha_t - (alphaStep_tr * x)), x1 + w - r, y1 + r); + BE_DRAWCIRCLE_BCOLOR_BR_CCW_CLIP(ptr_br, x, y, px, py, (uint8)(alpha_r - (alphaStep_br * x)), x1 + w - r, y1 + h - r); + BE_DRAWCIRCLE_BCOLOR_BL_CCW_CLIP(ptr_bl, x, y, px, py, (uint8)(alpha_b - (alphaStep_bl * x)), x1 + r, y1 + h - r); + BE_DRAWCIRCLE_BCOLOR_TL_CCW_CLIP(ptr_tl, x, y, px, py, (uint8)(alpha_l - (alphaStep_tl * x)), x1 + r, y1 + r); + + if (Base::_strokeWidth > 1) { + BE_DRAWCIRCLE_BCOLOR_CLIP(ptr_tr, ptr_tl, ptr_bl, ptr_br, x - 1, y, px, py, + x1 + w - r, y1 + r, x1 + r, y1 + r, x1 + r, y1 + h - r, x1 + w - r, y1 + h - r); + BE_DRAWCIRCLE_BCOLOR_CLIP(ptr_tr, ptr_tl, ptr_bl, ptr_br, x, y, px - pitch, py, + x1 + w - r, y1 + r, x1 + r, y1 + r, x1 + r, y1 + h - r, x1 + w - r, y1 + h - r); + } + } + } + + ptr_fill += pitch * real_radius; + while (short_h--) { + blendFillClip(ptr_fill, ptr_fill + Base::_strokeWidth, color1, alpha_l, + x1, y1 + real_radius + h - (2 * r) + 2 - short_h - 1); // left + blendFillClip(ptr_fill + w - Base::_strokeWidth + 1, ptr_fill + w + 1, color2, alpha_r, + x1 + w - Base::_strokeWidth + 1, y1 + real_radius + h - (2 * r) + 2 - short_h - 1); // right + ptr_fill += pitch; + } +} + +template<typename PixelType> +void VectorRendererSpec<PixelType>:: drawInteriorRoundedSquareAlg(int x1, int y1, int r, int w, int h, PixelType color, VectorRenderer::FillMode fill_m) { + // Do not draw empty space rounded squares. + if (w <= 0 || h <= 0) { + return; + } + int f, ddF_x, ddF_y; int x, y, px, py; int pitch = _activeSurface->pitch / _activeSurface->format.bytesPerPixel; @@ -1710,6 +3171,8 @@ drawInteriorRoundedSquareAlg(int x1, int y1, int r, int w, int h, PixelType colo while (x++ < y) { BE_ALGORITHM(); + if (y1 + r + y < _clippingArea.top || y1 + r + y > _clippingArea.bottom) continue; + color1 = calcGradient(real_radius - x, long_h); color2 = calcGradient(real_radius - y, long_h); color3 = calcGradient(long_h - r + x, long_h); @@ -1751,6 +3214,91 @@ drawInteriorRoundedSquareAlg(int x1, int y1, int r, int w, int h, PixelType colo template<typename PixelType> void VectorRendererSpec<PixelType>:: +drawInteriorRoundedSquareAlgClip(int x1, int y1, int r, int w, int h, PixelType color, VectorRenderer::FillMode fill_m) { + // Do not draw empty space rounded squares. + if (w <= 0 || h <= 0) { + return; + } + + int f, ddF_x, ddF_y; + int x, y, px, py; + int pitch = _activeSurface->pitch / _activeSurface->format.bytesPerPixel; + + PixelType *ptr_tl = (PixelType *)Base::_activeSurface->getBasePtr(x1 + r, y1 + r); + PixelType *ptr_tr = (PixelType *)Base::_activeSurface->getBasePtr(x1 + w - r, y1 + r); + PixelType *ptr_bl = (PixelType *)Base::_activeSurface->getBasePtr(x1 + r, y1 + h - r); + PixelType *ptr_br = (PixelType *)Base::_activeSurface->getBasePtr(x1 + w - r, y1 + h - r); + PixelType *ptr_fill = (PixelType *)Base::_activeSurface->getBasePtr(x1, y1); + + int real_radius = r; + int short_h = h - (2 * r) + 2; + int long_h = h; + + BE_RESET(); + + PixelType color1 = color; + + if (fill_m == kFillGradient) { + PixelType color2, color3, color4; + precalcGradient(long_h); + + while (x++ < y) { + BE_ALGORITHM(); + + color1 = calcGradient(real_radius - x, long_h); + color2 = calcGradient(real_radius - y, long_h); + color3 = calcGradient(long_h - r + x, long_h); + color4 = calcGradient(long_h - r + y, long_h); + + //TL = (x1 + r, y1 + r) + gradientFillClip(ptr_tl - x - py, w - 2 * r + 2 * x, x1 + r - x - y, real_radius - y, + x1 + r - x, y1 + r - y); + gradientFillClip(ptr_tl - y - px, w - 2 * r + 2 * y, x1 + r - y - x, real_radius - x, + x1 + r - y, y1 + r - x); + + //BL = (x1 + r, y1 + h - r) + gradientFillClip(ptr_bl - x + py, w - 2 * r + 2 * x, x1 + r - x - y, long_h - r + y, + x1 + r - x, y1 + h - r + y); + gradientFillClip(ptr_bl - y + px, w - 2 * r + 2 * y, x1 + r - y - x, long_h - r + x, + x1 + r - y, y1 + h - r + x); + + BE_DRAWCIRCLE_XCOLOR_CLIP(ptr_tr, ptr_tl, ptr_bl, ptr_br, x, y, px, py, + x1 + w - r, y1 + r, x1 + r, y1 + r, x1 + r, y1 + h - r, x1 + w - r, y1 + h - r); + } + } else { + while (x++ < y) { + BE_ALGORITHM(); + + colorFillClip<PixelType>(ptr_tl - x - py, ptr_tr + x - py, color1, + x1 + r - x, y1 + r - y, _clippingArea); + colorFillClip<PixelType>(ptr_tl - y - px, ptr_tr + y - px, color1, + x1 + r - y, y1 + r - x, _clippingArea); + + colorFillClip<PixelType>(ptr_bl - x + py, ptr_br + x + py, color1, + x1 + r - x, y1 + h - r + y, _clippingArea); + colorFillClip<PixelType>(ptr_bl - y + px, ptr_br + y + px, color1, + x1 + r - y, y1 + h - r + x, _clippingArea); + + // do not remove - messes up the drawing at lower resolutions + BE_DRAWCIRCLE_CLIP(ptr_tr, ptr_tl, ptr_bl, ptr_br, x, y, px, py, + x1 + w - r, y1 + r, x1 + r, y1 + r, x1 + r, y1 + h - r, x1 + w - r, y1 + h - r); + } + } + + ptr_fill += pitch * r; + int short_h_orig = short_h; + while (short_h--) { + if (fill_m == kFillGradient) { + gradientFillClip(ptr_fill, w + 1, x1, real_radius++, x1, y1 + r + short_h_orig - short_h -1); + } else { + colorFillClip<PixelType>(ptr_fill, ptr_fill + w + 1, color1, x1, y1 + r + short_h_orig - short_h - 1, _clippingArea); + } + ptr_fill += pitch; + } +} + +template<typename PixelType> +void VectorRendererSpec<PixelType>:: drawRoundedSquareAlg(int x1, int y1, int r, int w, int h, PixelType color, VectorRenderer::FillMode fill_m) { const uint8 borderAlpha_t = 0; const uint8 borderAlpha_r = 127; @@ -1780,6 +3328,38 @@ drawRoundedSquareAlg(int x1, int y1, int r, int w, int h, PixelType color, Vecto } } +template<typename PixelType> +void VectorRendererSpec<PixelType>:: +drawRoundedSquareAlgClip(int x1, int y1, int r, int w, int h, PixelType color, VectorRenderer::FillMode fill_m) { + const uint8 borderAlpha_t = 0; + const uint8 borderAlpha_r = 127; + const uint8 borderAlpha_b = 255; + const uint8 borderAlpha_l = 63; + + const uint8 bevelAlpha_t = 255; + const uint8 bevelAlpha_r = 31; + const uint8 bevelAlpha_b = 0; + const uint8 bevelAlpha_l = 127; + + // If only border is visible + if ((!(w <= 0 || h <= 0)) && (fill_m != Base::kFillDisabled)) { + if (fill_m == Base::kFillBackground) + drawInteriorRoundedSquareAlgClip(x1, y1, r, w, h, _bgColor, fill_m); + else + drawInteriorRoundedSquareAlgClip(x1, y1, r, w, h, color, fill_m); + } + + //I expect these to work fine with clipping: + if (Base::_strokeWidth) { + if (r != 0 && _bevel > 0) { + drawBorderRoundedSquareAlgClip(x1, y1, r, w, h, color, fill_m, borderAlpha_t, borderAlpha_r, borderAlpha_b, borderAlpha_l); + drawBorderRoundedSquareAlgClip(x1, y1, r, w, h, _bevelColor, fill_m, bevelAlpha_t, bevelAlpha_r, bevelAlpha_b, bevelAlpha_l); + } else { + drawBorderRoundedSquareAlgClip(x1, y1, r, w, h, color, fill_m, 255, 255, 255, 255); + } + } +} + /** CIRCLE ALGORITHM **/ template<typename PixelType> void VectorRendererSpec<PixelType>:: @@ -1824,7 +3404,47 @@ drawCircleAlg(int x1, int y1, int r, PixelType color, VectorRenderer::FillMode f } +template<typename PixelType> +void VectorRendererSpec<PixelType>:: +drawCircleAlgClip(int x1, int y1, int r, PixelType color, VectorRenderer::FillMode fill_m) { + int f, ddF_x, ddF_y; + int x, y, px, py, sw = 0; + int pitch = _activeSurface->pitch / _activeSurface->format.bytesPerPixel; + PixelType *ptr = (PixelType *)Base::_activeSurface->getBasePtr(x1, y1); + + if (fill_m == kFillDisabled) { + while (sw++ < Base::_strokeWidth) { + BE_RESET(); + r--; + + if (IS_IN_CLIP(x1 + y, y1)) *(ptr + y) = color; + if (IS_IN_CLIP(x1 - y, y1)) *(ptr - y) = color; + if (IS_IN_CLIP(x1, y1 + y)) *(ptr + py) = color; + if (IS_IN_CLIP(x1, y1 - y)) *(ptr - py) = color; + + while (x++ < y) { + BE_ALGORITHM(); + BE_DRAWCIRCLE_CLIP(ptr, ptr, ptr, ptr, x, y, px, py, x1, y1, x1, y1, x1, y1, x1, y1); + + if (Base::_strokeWidth > 1) { + BE_DRAWCIRCLE_CLIP(ptr, ptr, ptr, ptr, x - 1, y, px, py, x1, y1, x1, y1, x1, y1, x1, y1); + BE_DRAWCIRCLE_CLIP(ptr, ptr, ptr, ptr, x, y, px - pitch, py, x1, y1, x1, y1, x1, y1, x1, y1); + } + } + } + } else { + colorFillClip<PixelType>(ptr - r, ptr + r, color, x1 - r, y1 + r, _clippingArea); + BE_RESET(); + while (x++ < y) { + BE_ALGORITHM(); + colorFillClip<PixelType>(ptr - x + py, ptr + x + py, color, x1 - x, y1 + y, _clippingArea); + colorFillClip<PixelType>(ptr - x - py, ptr + x - py, color, x1 - x, y1 - y, _clippingArea); + colorFillClip<PixelType>(ptr - y + px, ptr + y + px, color, x1 - y, y1 + x, _clippingArea); + colorFillClip<PixelType>(ptr - y - px, ptr + y - px, color, x1 - y, y1 - x, _clippingArea); + } + } +} /******************************************************************** @@ -1835,6 +3455,11 @@ drawCircleAlg(int x1, int y1, int r, PixelType color, VectorRenderer::FillMode f template<typename PixelType> void VectorRendererSpec<PixelType>:: drawSquareShadow(int x, int y, int w, int h, int offset) { + // Do nothing for empty rects or no shadow offset. + if (w <= 0 || h <= 0 || offset <= 0) { + return; + } + PixelType *ptr = (PixelType *)_activeSurface->getBasePtr(x + w - 1, y + offset); int pitch = _activeSurface->pitch / _activeSurface->format.bytesPerPixel; int i, j; @@ -1870,6 +3495,54 @@ drawSquareShadow(int x, int y, int w, int h, int offset) { template<typename PixelType> void VectorRendererSpec<PixelType>:: +drawSquareShadowClip(int x, int y, int w, int h, int offset) { + // Do nothing for empty rects or no shadow offset. + if (w <= 0 || h <= 0 || offset <= 0) { + return; + } + + PixelType *ptr = (PixelType *)_activeSurface->getBasePtr(x + w - 1, y + offset); + int pitch = _activeSurface->pitch / _activeSurface->format.bytesPerPixel; + int i, j, ptr_x = x+w-1, ptr_y = y+offset; + + i = h - offset; + + while (i--) { + j = offset; + while (j--) + blendPixelPtrClip(ptr + j, 0, ((offset - j) << 8) / offset, ptr_x + j, ptr_y); + ptr += pitch; + ++ptr_y; + } + + ptr = (PixelType *)_activeSurface->getBasePtr(x + offset, y + h - 1); + ptr_x = x + offset; + ptr_y = y + h - 1; + + while (i++ < offset) { + j = w - offset; + while (j--) + blendPixelPtrClip(ptr + j, 0, ((offset - i) << 8) / offset, ptr_x + j, ptr_y); + ptr += pitch; + ++ptr_y; + } + + ptr = (PixelType *)_activeSurface->getBasePtr(x + w, y + h); + ptr_x = x + w; + ptr_y = y + h; + + i = 0; + while (i++ < offset) { + j = offset - 1; + while (j--) + blendPixelPtrClip(ptr + j, 0, (((offset - j) * (offset - i)) << 8) / (offset * offset), ptr_x + j, ptr_y); + ptr += pitch; + ++ptr_y; + } +} + +template<typename PixelType> +void VectorRendererSpec<PixelType>:: drawRoundedSquareShadow(int x1, int y1, int r, int w, int h, int offset) { int pitch = _activeSurface->pitch / _activeSurface->format.bytesPerPixel; @@ -1907,7 +3580,6 @@ drawRoundedSquareShadow(int x1, int y1, int r, int w, int h, int offset) { while (x++ < y) { BE_ALGORITHM(); - if (((1 << x) & hb) == 0) { blendFill(ptr_tl - y - px, ptr_tr + y - px, color, (uint8)alpha); @@ -1943,6 +3615,83 @@ drawRoundedSquareShadow(int x1, int y1, int r, int w, int h, int offset) { } } +template<typename PixelType> +void VectorRendererSpec<PixelType>:: +drawRoundedSquareShadowClip(int x1, int y1, int r, int w, int h, int offset) { + int pitch = _activeSurface->pitch / _activeSurface->format.bytesPerPixel; + + // "Harder" shadows when having lower BPP, since we will have artifacts (greenish tint on the modern theme) + uint8 expFactor = 3; + uint16 alpha = (_activeSurface->format.bytesPerPixel > 2) ? 4 : 8; + + // These constants ensure a border of 2px on the left and of each rounded square + int xstart = (x1 > 2) ? x1 - 2 : x1; + int ystart = y1; + int width = w + offset + 2; + int height = h + offset + 1; + + for (int i = offset; i >= 0; i--) { + int f, ddF_x, ddF_y; + int x, y, px, py; + + PixelType *ptr_tl = (PixelType *)Base::_activeSurface->getBasePtr(xstart + r, ystart + r); + PixelType *ptr_tr = (PixelType *)Base::_activeSurface->getBasePtr(xstart + width - r, ystart + r); + PixelType *ptr_bl = (PixelType *)Base::_activeSurface->getBasePtr(xstart + r, ystart + height - r); + PixelType *ptr_br = (PixelType *)Base::_activeSurface->getBasePtr(xstart + width - r, ystart + height - r); + PixelType *ptr_fill = (PixelType *)Base::_activeSurface->getBasePtr(xstart, ystart); + + int short_h = height - (2 * r) + 2; + PixelType color = _format.RGBToColor(0, 0, 0); + + BE_RESET(); + + // HACK: As we are drawing circles exploting 8-axis symmetry, + // there are 4 pixels on each circle which are drawn twice. + // this is ok on filled circles, but when blending on surfaces, + // we cannot let it blend twice. awful. + uint32 hb = 0; + + while (x++ < y) { + BE_ALGORITHM(); + + if (((1 << x) & hb) == 0) { + blendFillClip(ptr_tl - y - px, ptr_tr + y - px, color, (uint8)alpha, + xstart + r - y, ystart + r - x); + + // Will create a dark line of pixles if left out + if (hb > 0) { + blendFillClip(ptr_bl - y + px, ptr_br + y + px, color, (uint8)alpha, + xstart + r - y, ystart + height - r + x); + } + hb |= (1 << x); + } + + if (((1 << y) & hb) == 0) { + blendFillClip(ptr_tl - x - py, ptr_tr + x - py, color, (uint8)alpha, xstart + r - x, ystart + r - y); + blendFillClip(ptr_bl - x + py, ptr_br + x + py, color, (uint8)alpha, xstart + r - x, ystart + height - r + y); + hb |= (1 << y); + } + } + + ptr_fill += pitch * r; + int orig_short_h = short_h; + while (short_h--) { + blendFillClip(ptr_fill, ptr_fill + width + 1, color, (uint8)alpha, + xstart, ystart + r + orig_short_h - short_h - 1); + ptr_fill += pitch; + } + + // Make shadow smaller each iteration, and move it one pixel inward + xstart += 1; + ystart += 1; + width -= 2; + height -= 2; + + if (_shadowFillMode == kShadowExponential) + // Multiply with expfactor + alpha = (alpha * (expFactor << 8)) >> 9; + } +} /******************************************************************************/ @@ -1956,8 +3705,7 @@ drawRoundedSquareShadow(int x1, int y1, int r, int w, int h, int offset) { /** LINES **/ template<typename PixelType> void VectorRendererAA<PixelType>:: -drawLineAlg(int x1, int y1, int x2, int y2, int dx, int dy, PixelType color) { - +drawLineAlg(int x1, int y1, int x2, int y2, uint dx, uint dy, PixelType color) { PixelType *ptr = (PixelType *)Base::_activeSurface->getBasePtr(x1, y1); int pitch = Base::_activeSurface->pitch / Base::_activeSurface->format.bytesPerPixel; int xdir = (x2 > x1) ? 1 : -1; @@ -1967,7 +3715,7 @@ drawLineAlg(int x1, int y1, int x2, int y2, int dx, int dy, PixelType color) { *ptr = (PixelType)color; if (dx > dy) { - gradient = (uint32)(dy << 16) / (uint32)dx; + gradient = (dy << 16) / dx; error_acc = 0; while (--dx) { @@ -1983,8 +3731,8 @@ drawLineAlg(int x1, int y1, int x2, int y2, int dx, int dy, PixelType color) { this->blendPixelPtr(ptr, color, ~alpha); this->blendPixelPtr(ptr + pitch, color, alpha); } - } else { - gradient = (uint32)(dx << 16) / (uint32)dy; + } else if (dy != 0) { + gradient = (dx << 16) / dy; error_acc = 0; while (--dy) { @@ -2009,6 +3757,11 @@ drawLineAlg(int x1, int y1, int x2, int y2, int dx, int dy, PixelType color) { template<typename PixelType> void VectorRendererAA<PixelType>:: drawTabAlg(int x1, int y1, int w, int h, int r, PixelType color, VectorRenderer::FillMode fill_m, int baseLeft, int baseRight) { + // Don't draw anything for empty rects. + if (w <= 0 || h <= 0) { + return; + } + int x, y, px, py; int pitch = Base::_activeSurface->pitch / Base::_activeSurface->format.bytesPerPixel; int sw = 0, sp = 0, hp = 0; @@ -2217,6 +3970,14 @@ drawBorderRoundedSquareAlg(int x1, int y1, int r, int w, int h, PixelType color, template<typename PixelType> void VectorRendererAA<PixelType>:: drawInteriorRoundedSquareAlg(int x1, int y1, int r, int w, int h, PixelType color, VectorRenderer::FillMode fill_m) { + w -= 2*Base::_strokeWidth; + h -= 2*Base::_strokeWidth; + + // Do not draw empty space rounded squares. + if (w <= 0 || h <= 0) { + return; + } + int x, y; const int pitch = Base::_activeSurface->pitch / Base::_activeSurface->format.bytesPerPixel; int px, py; @@ -2228,8 +3989,6 @@ drawInteriorRoundedSquareAlg(int x1, int y1, int r, int w, int h, PixelType colo r -= Base::_strokeWidth; x1 += Base::_strokeWidth; y1 += Base::_strokeWidth; - w -= 2*Base::_strokeWidth; - h -= 2*Base::_strokeWidth; rsq = r*r; PixelType *ptr_tl = (PixelType *)Base::_activeSurface->getBasePtr(x1 + r, y1 + r); |