00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
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);
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:
00180 *reinterpret_cast<Uint8*>(PixelOffset) = static_cast<Uint8>(MixColor(ReadPoint(Point), PointColor).SDLColor(m_pSurface->format));
00181 break;
00182 case 2:
00183 *reinterpret_cast<Uint16*>(PixelOffset) = static_cast<Uint16>(MixColor(ReadPoint(Point), PointColor).SDLColor(m_pSurface->format));
00184 break;
00185 case 3:
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:
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:
00218 PixelColor = *reinterpret_cast<Uint8*>(PixelOffset);
00219 break;
00220 case 2:
00221 PixelColor = *reinterpret_cast<Uint16*>(PixelOffset);
00222 break;
00223 case 3:
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:
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