wg_painter.cpp

00001 // wg_painter.cpp
00002 //
00003 // CPainter class
00004 //
00005 //
00006 // Copyright (c) 2002-2004 Rob Wiskow
00007 // rob-dev@boxedchaos.com
00008 //
00009 // This library is free software; you can redistribute it and/or
00010 // modify it under the terms of the GNU Lesser General Public
00011 // License as published by the Free Software Foundation; either
00012 // version 2.1 of the License, or (at your option) any later version.
00013 //
00014 // This library is distributed in the hope that it will be useful,
00015 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00016 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
00017 // Lesser General Public License for more details.
00018 //
00019 // You should have received a copy of the GNU Lesser General Public
00020 // License along with this library; if not, write to the Free Software
00021 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
00022 //
00023 
00024 
00025 #include "wgui_include_config.h"
00026 #include "wg_painter.h"
00027 #include "wg_error.h"
00028 #include "std_ex.h"
00029 #include <algorithm>
00030 
00031 
00032 namespace wGui
00033 {
00034 
00035 CPainter::CPainter(SDL_Surface* pSurface, EPaintMode ePaintMode) :
00036      m_pSurface(pSurface),
00037      m_pWindow(0),
00038      m_PaintMode(ePaintMode)
00039 {
00040      if (!m_pSurface)
00041      {
00042           throw Wg_Ex_App(L"CPainter::CPainter : Invalid pointer to surface.");
00043      }
00044 }
00045 
00046 
00047 CPainter::CPainter(CWindow* pWindow, EPaintMode ePaintMode) :
00048      m_pSurface(0),
00049      m_pWindow(pWindow),
00050      m_PaintMode(ePaintMode)
00051 {
00052      if (!m_pWindow)
00053      {
00054           throw Wg_Ex_App(L"CPainter::CPainter : Invalid pointer to window.");
00055      }
00056      m_pSurface = pWindow->GetSDLSurface();
00057      if (!m_pSurface)
00058      {
00059           throw Wg_Ex_App(L"CPainter::CPainter : Invalid pointer to surface.");
00060      }
00061 }
00062 
00063 
00064 void CPainter::DrawHLine(int xStart, int xEnd, int y, const CRGBColor& LineColor)
00065 {
00066      if (m_pWindow)
00067      {
00068           CPoint Offset = m_pWindow->GetClientRect().TopLeft();
00069           xStart += Offset.XPos();
00070           xEnd += Offset.XPos();
00071           y += Offset.YPos();
00072      }
00073      SDL_Rect Rect;
00074      Rect.x = stdex::safe_static_cast<short int>(std::min(xStart, xEnd));
00075      Rect.y = stdex::safe_static_cast<short int>(y);
00076      Rect.w = stdex::safe_static_cast<short int>(std::max(xEnd - xStart + 1, xStart - xEnd + 1));
00077      Rect.h = 1;
00078      SDL_FillRect(m_pSurface, &Rect, LineColor.SDLColor(m_pSurface->format));
00079 }
00080 
00081 
00082 void CPainter::DrawVLine(int yStart, int yEnd, int x, const CRGBColor& LineColor)
00083 {
00084      if (m_pWindow)
00085      {
00086           CPoint Offset = m_pWindow->GetClientRect().TopLeft();
00087           yStart += Offset.YPos();
00088           yEnd += Offset.YPos();
00089           x += Offset.XPos();
00090      }
00091      SDL_Rect Rect;
00092      Rect.x = stdex::safe_static_cast<short int>(x);
00093      Rect.y = stdex::safe_static_cast<short int>(std::min(yStart, yEnd));
00094      Rect.w = 1;
00095      Rect.h = stdex::safe_static_cast<short int>(std::max(yEnd - yStart + 1, yStart - yEnd + 1));
00096      SDL_FillRect(m_pSurface, &Rect, LineColor.SDLColor(m_pSurface->format));
00097 }
00098 
00099 
00100 void CPainter::DrawRect(const CRect& Rect, bool bFilled, const CRGBColor& BorderColor, const CRGBColor& FillColor)
00101 {
00102      CRect RealRect(Rect);
00103      if (m_pWindow)
00104      {
00105           RealRect = Rect + m_pWindow->GetClientRect().TopLeft();
00106           RealRect.ClipTo(m_pWindow->GetClientRect());
00107      }
00108      if (!bFilled || (BorderColor != FillColor))
00109      {
00110           DrawHLine(RealRect.Left(), RealRect.Right(), RealRect.Top(), BorderColor);
00111           DrawHLine(RealRect.Left(), RealRect.Right(), RealRect.Bottom(), BorderColor);
00112           DrawVLine(RealRect.Top(), RealRect.Bottom(), RealRect.Left(), BorderColor);
00113           DrawVLine(RealRect.Top(), RealRect.Bottom(), RealRect.Right(), BorderColor);
00114           RealRect.Grow(-1); //In case we have to fill the rect, then it's ready to go.
00115      }
00116 
00117      if (bFilled)
00118      {
00119           if (m_PaintMode == PAINT_REPLACE)
00120           {
00121                SDL_Rect FillRect = RealRect.SDLRect();
00122                SDL_FillRect(m_pSurface, &FillRect, FillColor.SDLColor(m_pSurface->format));
00123           }
00124           else
00125           {
00126                for (int iY = RealRect.Top(); iY <= RealRect.Bottom(); ++iY)
00127                {
00128                     for (int iX = RealRect.Left(); iX <= RealRect.Right(); ++iX)
00129                     {
00130                          DrawPoint(CPoint(iX, iY), FillColor);
00131                     }
00132                }
00133           }
00134      }
00135 }
00136 
00137 
00138 void CPainter::DrawLine(const CPoint& Point1, const CPoint& Point2, const CRGBColor& LineColor)
00139 {
00140      if (Point1.XPos() == Point2.XPos())
00141      {
00142           DrawVLine(Point1.YPos(), Point2.YPos(), Point1.XPos(), LineColor);
00143      }
00144      else
00145      {
00146           double iSlope = double(Point2.YPos() - Point1.YPos()) / (Point2.XPos() - Point1.XPos());
00147           if (iSlope <= 1 && iSlope >= -1)
00148           {
00149                CPoint StartPoint = (Point1.XPos() < Point2.XPos()) ? Point1 : Point2;
00150                CPoint EndPoint = (Point1.XPos() < Point2.XPos()) ? Point2 : Point1;
00151                for (int x = StartPoint.XPos(); x <= EndPoint.XPos(); ++x)
00152                {
00153                     DrawPoint(CPoint(x, stdex::safe_static_cast<int>(StartPoint.YPos() + (x - StartPoint.XPos()) * iSlope)), LineColor);
00154                }
00155           }
00156           else
00157           {
00158                CPoint StartPoint = (Point1.YPos() < Point2.YPos()) ? Point1 : Point2;
00159                CPoint EndPoint = (Point1.YPos() < Point2.YPos()) ? Point2 : Point1;
00160                for (int y = StartPoint.YPos(); y <= EndPoint.YPos(); ++y)
00161                {
00162                     DrawPoint(CPoint(stdex::safe_static_cast<int>(StartPoint.XPos() + (y - StartPoint.YPos()) / iSlope), y), LineColor);
00163                }
00164           }
00165      }
00166 }
00167 
00168 
00169 void CPainter::DrawPoint(const CPoint& Point, const CRGBColor& PointColor)
00170 {
00171      CPoint RealPoint = (m_pWindow != 0) ? Point + m_pWindow->GetClientRect().TopLeft() : Point;
00172      if (CRect(0, 0, m_pSurface->w, m_pSurface->h).HitTest(RealPoint) == CRect::RELPOS_INSIDE)
00173      {
00174           LockSurface();
00175           Uint8* PixelOffset = static_cast<Uint8*>(m_pSurface->pixels) +
00176                m_pSurface->format->BytesPerPixel * RealPoint.XPos() + m_pSurface->pitch * RealPoint.YPos();
00177           switch (m_pSurface->format->BytesPerPixel)
00178           {
00179           case 1: // 8 bpp
00180                *reinterpret_cast<Uint8*>(PixelOffset) = static_cast<Uint8>(MixColor(ReadPoint(Point), PointColor).SDLColor(m_pSurface->format));
00181                break;
00182           case 2: // 16 bpp
00183                *reinterpret_cast<Uint16*>(PixelOffset) = static_cast<Uint16>(MixColor(ReadPoint(Point), PointColor).SDLColor(m_pSurface->format));
00184                break;
00185           case 3:  // 24 bpp
00186           {
00187                Uint32 PixelColor = MixColor(ReadPoint(Point), PointColor).SDLColor(m_pSurface->format);
00188                Uint8* pPixelSource = reinterpret_cast<Uint8*>(&PixelColor);
00189                Uint8* pPixelDest = reinterpret_cast<Uint8*>(PixelOffset);
00190                *pPixelDest = *pPixelSource;
00191                *(++pPixelDest) = *(++pPixelSource);
00192                *(++pPixelDest) = *(++pPixelSource);
00193                break;
00194           }
00195           case 4: // 32 bpp
00196                *reinterpret_cast<Uint32*>(PixelOffset) = static_cast<Uint32>(MixColor(ReadPoint(Point), PointColor).SDLColor(m_pSurface->format));
00197                break;
00198           default:
00199                throw(Wg_Ex_SDL(L"CPainter::DrawPoint : Unrecognized BytesPerPixel."));
00200                break;
00201           }
00202           UnlockSurface();
00203      }
00204 }
00205 
00206 
00207 CRGBColor CPainter::ReadPoint(const CPoint& Point)
00208 {
00209      CPoint RealPoint = (m_pWindow != 0) ? Point + m_pWindow->GetClientRect().TopLeft() : Point;
00210      Uint32 PixelColor = 0;
00211      if (CRect(0, 0, m_pSurface->w, m_pSurface->h).HitTest(RealPoint) == CRect::RELPOS_INSIDE)
00212      {
00213           Uint8* PixelOffset = static_cast<Uint8*>(m_pSurface->pixels) +
00214                m_pSurface->format->BytesPerPixel * RealPoint.XPos() + m_pSurface->pitch * RealPoint.YPos();
00215           switch (m_pSurface->format->BytesPerPixel)
00216           {
00217           case 1: // 8 bpp
00218                PixelColor = *reinterpret_cast<Uint8*>(PixelOffset);
00219                break;
00220           case 2: // 16 bpp
00221                PixelColor = *reinterpret_cast<Uint16*>(PixelOffset);
00222                break;
00223           case 3: // 24 bpp
00224           {
00225                Uint8* pPixelDest = reinterpret_cast<Uint8*>(&PixelColor);
00226                Uint8* pPixelSource = reinterpret_cast<Uint8*>(PixelOffset);
00227                *pPixelDest = *pPixelSource;
00228                *(++pPixelDest) = *(++pPixelSource);
00229                *(++pPixelDest) = *(++pPixelSource);
00230                break;
00231           }
00232           case 4: // 32 bpp
00233                PixelColor = *reinterpret_cast<Uint32*>(PixelOffset);
00234                break;
00235           default:
00236                throw(Wg_Ex_SDL(L"CPainter::DrawPoint : Unrecognized BytesPerPixel."));
00237                break;
00238           }
00239      }
00240      return CRGBColor(&PixelColor, m_pSurface->format);
00241 }
00242 
00243 
00244 void CPainter::LockSurface(void)
00245 {
00246      if (SDL_MUSTLOCK(m_pSurface))
00247      {
00248           if (SDL_LockSurface(m_pSurface) < 0)
00249           {
00250                SDL_Delay(10);
00251                if (SDL_LockSurface(m_pSurface) < 0)
00252                {
00253                     throw(Wg_Ex_SDL(L"Unable to lock surface."));
00254                }
00255           }
00256      }
00257 }
00258 
00259 
00260 void CPainter::UnlockSurface(void)
00261 {
00262      if (SDL_MUSTLOCK(m_pSurface))
00263      {
00264           SDL_UnlockSurface(m_pSurface);
00265      }
00266 }
00267 
00268 
00269 CRGBColor CPainter::MixColor(const CRGBColor& ColorBase, const CRGBColor& ColorAdd)
00270 {
00271      CRGBColor MixedColor(COLOR_TRANSPARENT);
00272      switch (m_PaintMode)
00273      {
00274      case PAINT_IGNORE:
00275           MixedColor = ColorBase;
00276           break;
00277      case PAINT_REPLACE:
00278           MixedColor = ColorAdd;
00279           break;
00280      case PAINT_NORMAL:
00281           MixedColor = ColorBase.MixNormal(ColorAdd);
00282           break;
00283      case PAINT_AND:
00284           MixedColor = ColorBase & ColorAdd;
00285           break;
00286      case PAINT_OR:
00287           MixedColor = ColorBase | ColorAdd;
00288           break;
00289      case PAINT_XOR:
00290           MixedColor = ColorBase ^ ColorAdd;
00291           break;
00292      case PAINT_ADDITIVE:
00293           MixedColor = ColorBase + ColorAdd;
00294           break;
00295      }
00296 
00297      return MixedColor;
00298 }
00299 
00300 
00301 void CPainter::ReplaceColor(const CRGBColor& NewColor, const CRGBColor& OldColor)
00302 {
00303      for (int y = 0; y < m_pSurface->h; ++y)
00304      {
00305           for (int x = 0; x < m_pSurface->w; ++x)
00306           {
00307                CPoint point(x, y);
00308                if(ReadPoint(point) == OldColor)
00309                {
00310                     DrawPoint(point, NewColor);
00311                }
00312           }
00313      }
00314 }
00315 
00316 
00317 void CPainter::TransparentColor(const CRGBColor& TransparentColor)
00318 {
00319      SDL_SetColorKey(m_pSurface, SDL_SRCCOLORKEY, TransparentColor.SDLColor(m_pSurface->format));
00320 }
00321 
00322 }
00323 

Generated on Wed May 16 23:11:26 2007 for wGui by  doxygen 1.5.1