From 55cfae33e9b54d10b602eb9ecc52aee294408a2f Mon Sep 17 00:00:00 2001 From: Vicent Marti Date: Sun, 18 May 2008 00:18:15 +0000 Subject: - Shadows revisited. - Test rendering... starting to look like a GUI. svn-id: r32164 --- graphics/VectorRenderer.cpp | 120 ++++++++++++++++++++++++++++++++++---------- graphics/VectorRenderer.h | 118 ++++++++++++++++++++----------------------- 2 files changed, 148 insertions(+), 90 deletions(-) diff --git a/graphics/VectorRenderer.cpp b/graphics/VectorRenderer.cpp index 47f46e3bcf..221f525820 100644 --- a/graphics/VectorRenderer.cpp +++ b/graphics/VectorRenderer.cpp @@ -81,19 +81,25 @@ void vector_renderer_test(OSystem *_system) { while (true) { // draw!! vr->setFgColor(255, 0, 206); - vr->fillSurface(); + vr->setGradientFactor(1); + vr->setGradientColors(214, 113, 8, 240, 200, 25); + vr->fillSurface(VectorRenderer::kGradientFill); - vr->setFgColor(255, 247, 222); vr->setBgColor(25, 25, 175); - vr->setGradientColors(206, 121, 99, 173, 40, 8); - vr->setFillMode(VectorRenderer::kGradientFill); + vr->shadowEnable(3); + vr->setFgColor(240, 204, 120); vr->setStrokeWidth(1); - vr->shadowEnable(1, 1); + vr->setFillMode(VectorRenderer::kGradientFill); - vr->drawLine(25, 25, 125, 300); - vr->drawCircle(250, 250, 100); - vr->drawSquare(150, 25, 100, 75); - vr->drawRoundedSquare(275, 25, 16, 128, 128); + vr->setGradientFactor(3); + vr->setGradientColors(255, 231, 140, 255, 243, 206); + vr->drawRoundedSquare(25, 95, 18, 465, 290); + + vr->setGradientFactor(1); + vr->setGradientColors(206, 121, 99, 173, 40, 8); + vr->drawRoundedSquare(500, 95, 8, 120, 30); + vr->drawRoundedSquare(500, 135, 8, 120, 30); + vr->drawRoundedSquare(500, 175, 8, 120, 30); _system->copyRectToOverlay((OverlayColor*)_screen.getBasePtr(0, 0), _screen.w, 0, 0, _screen.w, _screen.w); _system->updateScreen(); @@ -111,13 +117,14 @@ void vector_renderer_test(OSystem *_system) { template void VectorRendererSpec:: drawCircle(int x, int y, int r) { - if (Base::_fillMode != kNoFill && Base::_shadows) { - drawCircleAlg(x + Base::_shadowXOffset + 1, y + Base::_shadowYOffset + 1, r, 0, kForegroundFill); + if (Base::_fillMode != kNoFill && Base::_shadowOffset) { + drawCircleAlg(x + Base::_shadowOffset + 1, y + Base::_shadowOffset + 1, r, 0, kForegroundFill); } switch(Base::_fillMode) { case kNoFill: - drawCircleAlg(x, y, r, _fgColor, kNoFill); + if (Base::_strokeWidth) + drawCircleAlg(x, y, r, _fgColor, kNoFill); break; case kForegroundFill: @@ -125,8 +132,13 @@ drawCircle(int x, int y, int r) { break; case kBackgroundFill: - drawCircleAlg(x, y, r, _fgColor, kForegroundFill); - drawCircleAlg(x, y, r - Base::_strokeWidth, _bgColor, kBackgroundFill); + if (Base::_strokeWidth > 1) { + drawCircleAlg(x, y, r, _fgColor, kForegroundFill); + drawCircleAlg(x, y, r - Base::_strokeWidth, _bgColor, kBackgroundFill); + } else { + drawCircleAlg(x, y, r, _bgColor, kBackgroundFill); + drawCircleAlg(x, y, r, _fgColor, kNoFill); + } break; case kGradientFill: @@ -137,13 +149,14 @@ drawCircle(int x, int y, int r) { template void VectorRendererSpec:: drawSquare(int x, int y, int w, int h) { - if (Base::_fillMode != kNoFill && Base::_shadows) { - drawSquareShadow(x, y, w, h); + if (Base::_fillMode != kNoFill && Base::_shadowOffset) { + drawSquareShadow(x, y, w, h, Base::_shadowOffset); } switch(Base::_fillMode) { case kNoFill: - drawSquareAlg(x, y, w, h, _fgColor, kNoFill); + if (Base::_strokeWidth) + drawSquareAlg(x, y, w, h, _fgColor, kNoFill); break; case kForegroundFill: @@ -157,7 +170,8 @@ drawSquare(int x, int y, int w, int h) { case kGradientFill: VectorRendererSpec::drawSquareAlg(x, y, w, h, 0, kGradientFill); - drawSquareAlg(x, y, w, h, _fgColor, kNoFill); + if (Base::_strokeWidth) + drawSquareAlg(x, y, w, h, _fgColor, kNoFill); break; } } @@ -165,13 +179,14 @@ drawSquare(int x, int y, int w, int h) { template void VectorRendererSpec:: drawRoundedSquare(int x, int y, int r, int w, int h) { - if (Base::_fillMode != kNoFill && Base::_shadows) { - drawRoundedSquareShadow(x, y, r, w, h); + if (Base::_fillMode != kNoFill && Base::_shadowOffset) { + drawRoundedSquareShadow(x, y, r, w, h, Base::_shadowOffset); } switch(Base::_fillMode) { case kNoFill: - drawRoundedSquareAlg(x, y, r, w, h, _fgColor, kNoFill); + if (Base::_strokeWidth) + drawRoundedSquareAlg(x, y, r, w, h, _fgColor, kNoFill); break; case kForegroundFill: @@ -190,7 +205,8 @@ drawRoundedSquare(int x, int y, int r, int w, int h) { r - Base::_strokeWidth/2, w - Base::_strokeWidth, h - Base::_strokeWidth, 0, kGradientFill); } else { VectorRendererSpec::drawRoundedSquareAlg(x, y, r, w, h, 0, kGradientFill); - drawRoundedSquareAlg(x, y, r, w, h, _fgColor, kNoFill); + if (Base::_strokeWidth) + drawRoundedSquareAlg(x, y, r, w, h, _fgColor, kNoFill); } break; } @@ -230,8 +246,7 @@ drawSquareAlg(int x, int y, int w, int h, PixelType color, FillMode fill_m) { template void VectorRendererSpec:: -drawSquareShadow(int x, int y, int w, int h) { - int blur = 8; +drawSquareShadow(int x, int y, int w, int h, int blur) { PixelType *ptr = (PixelType *)_activeSurface->getBasePtr(x + w - 1, y + blur); int pitch = Base::surfacePitch(); int i, j; @@ -314,7 +329,7 @@ drawLineAlg(int x1, int y1, int x2, int y2, int dx, int dy, PixelType color) { template -void VectorRendererAA:: +void VectorRendererSpec:: blendPixelPtr(PixelType *ptr, PixelType color, uint8 alpha) { if (alpha == 255) { *ptr = color; @@ -404,6 +419,9 @@ drawLine(int x1, int y1, int x2, int y2) { if (dy == 0 && dx == 0) return; + if (Base::_strokeWidth == 0) + return; + PixelType *ptr = (PixelType *)_activeSurface->getBasePtr(x1, y1); int pitch = Base::surfacePitch(); @@ -507,8 +525,57 @@ drawCircleAlg(int x1, int y1, int r, PixelType color, FillMode fill_m) { template void VectorRendererSpec:: -drawRoundedSquareShadow(int x1, int y1, int r, int w, int h) { +drawRoundedSquareShadow(int x1, int y1, int r, int w, int h, int blur) { + int f, ddF_x, ddF_y; + int x, y, px, py; + int pitch = Base::surfacePitch(); + int sw = 0, sp = 0, hp = h * pitch; + int alpha = 102; + + x1 += blur; + y1 += blur; + + 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 + w - blur, y1 + r); + + int short_h = h - (2 * r) + 1; + + __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. + bool *hb = new bool[r]; + int i = 0; + while (i < r) + hb[i++] = false; + + while (x++ < y) { + __BE_ALGORITHM(); + + if (!hb[x]) { + blendFill(ptr_tr - px - r, ptr_tr + y - px, 0, alpha); + blendFill(ptr_bl - y + px, ptr_br + y + px, 0, alpha); + hb[x] = true; + } + + if (!hb[y]) { + blendFill(ptr_tr - r - py, ptr_tr + x - py, 0, alpha); + blendFill(ptr_bl - x + py, ptr_br + x + py, 0, alpha); + hb[y] = true; + } + } + + delete[] hb; + + while (short_h--) { + blendFill(ptr_fill - r, ptr_fill + blur, 0, alpha); + ptr_fill += pitch; + } } template @@ -577,6 +644,7 @@ drawRoundedSquareAlg(int x1, int y1, int r, int w, int h, PixelType color, FillM Common::set_to(ptr_bl - x + py, ptr_br + x + py, color); Common::set_to(ptr_bl - y + px, ptr_br + y + px, color); + // FIXME: maybe not needed at all? __BE_DRAWCIRCLE(ptr_tr, ptr_tl, ptr_bl, ptr_br, x, y, px, py); } } diff --git a/graphics/VectorRenderer.h b/graphics/VectorRenderer.h index b7b19a77e7..028b0ba74a 100644 --- a/graphics/VectorRenderer.h +++ b/graphics/VectorRenderer.h @@ -53,7 +53,7 @@ void vector_renderer_test(OSystem *_system); class VectorRenderer { public: - VectorRenderer() : _shadows(false), _fillMode(kNoFill), _activeSurface(NULL), _strokeWidth(1) {} + VectorRenderer() : _shadowOffset(0), _fillMode(kNoFill), _activeSurface(NULL), _strokeWidth(1), _gradientFactor(1) {} virtual ~VectorRenderer() {} enum FillMode { @@ -63,10 +63,10 @@ public: kGradientFill = 3 }; - enum ColorMode { +/* enum ColorMode { kForegroundColor, kBackgroundColor - }; + }; */ /** * Draws a line by considering the special cases for optimization. @@ -175,7 +175,7 @@ public: * * @param mode Color mode (bg or fg color) used to fill. */ - virtual void fillSurface(ColorMode mode = kForegroundColor) = 0; + virtual void fillSurface(FillMode mode = kForegroundFill) = 0; /** * Clears the active surface. @@ -202,7 +202,7 @@ public: * @param width Witdh of the stroke in pixels. */ virtual void setStrokeWidth(int width) { - if (width > 0) _strokeWidth = width; + _strokeWidth = width; } /** @@ -214,10 +214,9 @@ public: * @param y_offset Vertical offset for the shadows. * @see shadowDisable() */ - virtual void shadowEnable(int x_offset, int y_offset) { - _shadows = true; - _shadowXOffset = x_offset; - _shadowYOffset = y_offset; + virtual void shadowEnable(int offset) { + if (offset > 0) + _shadowOffset = offset; } /** @@ -226,7 +225,12 @@ public: * @see shadowEnable() */ virtual void shadowDisable() { - _shadows = false; + _shadowOffset = 0; + } + + virtual void setGradientFactor(int factor) { + if (factor > 0) + _gradientFactor = factor; } protected: @@ -234,11 +238,11 @@ protected: FillMode _fillMode; /** Defines in which way (if any) are filled the drawn shapes */ - bool _shadows; /** Defines if shadows are automatically added to drawn shapes */ - int _shadowXOffset; /** Horizontal offset for drawn shadows */ - int _shadowYOffset; /** Vertical offset for drawn shadows */ - + int _shadowOffset; /** offset for drawn shadows */ int _strokeWidth; /** Width of the stroke of all drawn shapes */ + + int _gradientFactor; + int _gradientBytes[3]; }; @@ -304,22 +308,32 @@ public: _gradientEnd = RGBToColor(r2, g2, b2); _gradientStart = RGBToColor(r1, g1, b1); - _gradientBytes[0] = (_gradientEnd & PixelFormat::kRedMask) - (_gradientStart & PixelFormat::kRedMask); - _gradientBytes[1] = (_gradientEnd & PixelFormat::kGreenMask) - (_gradientStart & PixelFormat::kGreenMask); - _gradientBytes[2] = (_gradientEnd & PixelFormat::kBlueMask) - (_gradientStart & PixelFormat::kBlueMask); + Base::_gradientBytes[0] = (_gradientEnd & PixelFormat::kRedMask) - (_gradientStart & PixelFormat::kRedMask); + Base::_gradientBytes[1] = (_gradientEnd & PixelFormat::kGreenMask) - (_gradientStart & PixelFormat::kGreenMask); + Base::_gradientBytes[2] = (_gradientEnd & PixelFormat::kBlueMask) - (_gradientStart & PixelFormat::kBlueMask); } /** * @see VectorRenderer::fillSurface() */ - void fillSurface(ColorMode mode = kForegroundColor) { + void fillSurface(FillMode mode = kForegroundFill) { PixelType *ptr = (PixelType *)_activeSurface->getBasePtr(0, 0); - int s = _activeSurface->w * _activeSurface->h; - if (mode == kBackgroundColor) - Common::set_to(ptr, ptr + s, _bgColor); - else if (mode == kForegroundColor) - Common::set_to(ptr, ptr + s, _fgColor); + int w = _activeSurface->w; + int h = _activeSurface->h ; + int pitch = surfacePitch(); + + if (mode == kBackgroundFill) + Common::set_to(ptr, ptr + w*h, _bgColor); + else if (mode == kForegroundFill) + Common::set_to(ptr, ptr + w*h, _fgColor); + else if (mode == kGradientFill) { + int i = h; + while (i--) { + Common::set_to(ptr, ptr + w, calcGradient(h - i, h)); + ptr += pitch; + } + } } protected: @@ -341,21 +355,19 @@ protected: * Blends a single pixel on the surface with the given coordinates, color * and Alpha intensity. * - * Note: Pixel blending is currently disabled on the Specialized Renderer - * because of performance issues. - * * @param x Horizontal coordinate of the pixel. * @param y Vertical coordinate of the pixel. * @param color Color of the pixel * @param alpha Alpha intensity of the pixel (0-255) */ virtual inline void blendPixel(int x, int y, PixelType color, uint8 alpha) { - putPixel(x, y, color); + if (alpha == 255) + putPixel(x, y, color); + else if (alpha > 0) + blendPixelPtr((PixelType*)Base::_activeSurface->getBasePtr(x, y), color, alpha); } - virtual inline void blendPixelPtr(PixelType *ptr, PixelType color, uint8 alpha) { - *ptr = (PixelType)color; - } + virtual inline void blendPixelPtr(PixelType *ptr, PixelType color, uint8 alpha); /* * "Bresenham's Line Algorithm", as described in Wikipedia. @@ -368,27 +380,31 @@ protected: virtual void drawCircleAlg(int x, int y, int r, PixelType color, FillMode fill_m); virtual void drawRoundedSquareAlg(int x1, int y1, int r, int w, int h, PixelType color, FillMode fill_m); virtual void drawSquareAlg(int x, int y, int w, int h, PixelType color, FillMode fill_m); - virtual void drawSquareShadow(int x, int y, int w, int h); - virtual void drawRoundedSquareShadow(int x, int y, int r, int w, int h); + virtual void drawSquareShadow(int x, int y, int w, int h, int blur); + virtual void drawRoundedSquareShadow(int x, int y, int r, int w, int h, int blur); - inline PixelType calcGradient(int pos, int max, int factor = 1) { + inline PixelType calcGradient(uint32 pos, uint32 max) { PixelType output = 0; - pos = (0x1000 * MIN(pos * factor, max)) / max; + pos = (MIN(pos * Base::_gradientFactor, max) << 12) / max; - output |= (_gradientStart + (_gradientBytes[0] * pos >> 12)) & PixelFormat::kRedMask; - output |= (_gradientStart + (_gradientBytes[1] * pos >> 12)) & PixelFormat::kGreenMask; - output |= (_gradientStart + (_gradientBytes[2] * pos >> 12)) & PixelFormat::kBlueMask; + output |= (_gradientStart + ((Base::_gradientBytes[0] * pos) >> 12)) & PixelFormat::kRedMask; + output |= (_gradientStart + ((Base::_gradientBytes[1] * pos) >> 12)) & PixelFormat::kGreenMask; + output |= (_gradientStart + ((Base::_gradientBytes[2] * pos) >> 12)) & PixelFormat::kBlueMask; output |= ~(PixelFormat::kRedMask | PixelFormat::kGreenMask | PixelFormat::kBlueMask); return output; } + inline void blendFill(PixelType *first, PixelType *last, PixelType color, uint8 alpha) { + while (first != last) + blendPixelPtr(first++, color, alpha); + } + PixelType _fgColor; /** Foreground color currently being used to draw on the renderer */ PixelType _bgColor; /** Background color currently being used to draw on the renderer */ PixelType _gradientStart; PixelType _gradientEnd; - int _gradientBytes[3]; }; /** @@ -418,32 +434,6 @@ protected: */ void drawLineAlg(int x1, int y1, int x2, int y2, int dx, int dy, PixelType color); - /** - * Perform alpha blending on top of a given pixel, not on a given - * coordinate (just so we don't have to recalculate the surface - * pointer while we are blending consecutive pixels). - * - * Everything from blendPixel() applies here. - * - * @see VectorRenderer::blendPixel() - * @param ptr Pointer to the pixel where we must draw - * @param alpha Intensity of the pixel (0-255). - */ - inline virtual void blendPixelPtr(PixelType *ptr, PixelType color, uint8 alpha); - - /** - * @see VectorRenderer::blendPixel() - * - * The AA renderer does support alpha blending. Special cases are - * handled separately. - */ - inline void blendPixel(int x, int y, PixelType color, uint8 alpha) { - if (alpha == 255) - putPixel(x, y, color); - else if (alpha > 0) - blendPixelPtr((PixelType*)Base::_activeSurface->getBasePtr(x, y), color, alpha); - } - /** * "Wu's Circle Antialiasing Algorithm" as published by Xiaolin Wu, July 1991 * Based on the theoretical concept of the algorithm. -- cgit v1.2.3