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
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046
00047
00048
00049
00050
00051
00052
00053
00054
00055
00056
00057
00058
00059
00060
00061 #include "guichan/sdl/sdlgraphics.hpp"
00062
00063 #include "guichan/exception.hpp"
00064 #include "guichan/font.hpp"
00065 #include "guichan/image.hpp"
00066 #include "guichan/sdl/sdlimage.hpp"
00067 #include "guichan/sdl/sdlpixel.hpp"
00068
00069
00070
00071 #ifndef ABS
00072 #define ABS(x) ((x)<0?-(x):(x))
00073 #endif
00074
00075 namespace gcn
00076 {
00077
00078 SDLGraphics::SDLGraphics()
00079 {
00080 mAlpha = false;
00081 }
00082
00083 void SDLGraphics::_beginDraw()
00084 {
00085 Rectangle area;
00086 area.x = 0;
00087 area.y = 0;
00088 area.width = mTarget->w;
00089 area.height = mTarget->h;
00090 pushClipArea(area);
00091 }
00092
00093 void SDLGraphics::_endDraw()
00094 {
00095 popClipArea();
00096 }
00097
00098 void SDLGraphics::setTarget(SDL_Surface* target)
00099 {
00100 mTarget = target;
00101 }
00102
00103 bool SDLGraphics::pushClipArea(Rectangle area)
00104 {
00105 SDL_Rect rect;
00106 bool result = Graphics::pushClipArea(area);
00107
00108 ClipRectangle carea = mClipStack.top();
00109 rect.x = carea.x;
00110 rect.y = carea.y;
00111 rect.w = carea.width;
00112 rect.h = carea.height;
00113
00114 SDL_SetClipRect(mTarget, &rect);
00115
00116 return result;
00117 }
00118
00119 void SDLGraphics::popClipArea()
00120 {
00121 SDL_Rect rect;
00122 Graphics::popClipArea();
00123
00124 if (mClipStack.empty())
00125 {
00126 return;
00127 }
00128
00129 ClipRectangle carea = mClipStack.top();
00130 rect.x = carea.x;
00131 rect.y = carea.y;
00132 rect.w = carea.width;
00133 rect.h = carea.height;
00134
00135 SDL_SetClipRect(mTarget, &rect);
00136 }
00137
00138 SDL_Surface* SDLGraphics::getTarget() const
00139 {
00140 return mTarget;
00141 }
00142
00143 void SDLGraphics::drawImage(const Image* image, int srcX,
00144 int srcY, int dstX, int dstY,
00145 int width, int height)
00146 {
00147 ClipRectangle top = mClipStack.top();
00148 SDL_Rect src;
00149 SDL_Rect dst;
00150 src.x = srcX;
00151 src.y = srcY;
00152 src.w = width;
00153 src.h = height;
00154 dst.x = dstX + top.xOffset;
00155 dst.y = dstY + top.yOffset;
00156
00157 const SDLImage* srcImage = dynamic_cast<const SDLImage*>(image);
00158
00159 if (srcImage == NULL)
00160 {
00161 throw GCN_EXCEPTION("Trying to draw an image of unknown format, must be an SDLImage.");
00162 }
00163
00164 SDL_BlitSurface(srcImage->getSurface(), &src, mTarget, &dst);
00165 }
00166
00167 void SDLGraphics::fillRectangle(const Rectangle& rectangle)
00168 {
00169 Rectangle area = rectangle;
00170 ClipRectangle top = mClipStack.top();
00171
00172 area.x += top.xOffset;
00173 area.y += top.yOffset;
00174
00175 if(!area.intersect(top))
00176 {
00177 return;
00178 }
00179
00180 if (mAlpha)
00181 {
00182 int x1 = area.x > top.x ? area.x : top.x;
00183 int y1 = area.y > top.y ? area.y : top.y;
00184 int x2 = area.x + area.width < top.x + top.width ? area.x + area.width : top.x + top.width;
00185 int y2 = area.y + area.height < top.y + top.height ? area.y + area.height : top.y + top.height;
00186 int x, y;
00187
00188 SDL_LockSurface(mTarget);
00189 for (y = y1; y < y2; y++)
00190 {
00191 for (x = x1; x < x2; x++)
00192 {
00193 SDLputPixelAlpha(mTarget, x, y, mColor);
00194 }
00195 }
00196 SDL_UnlockSurface(mTarget);
00197
00198 }
00199 else
00200 {
00201 SDL_Rect rect;
00202 rect.x = area.x;
00203 rect.y = area.y;
00204 rect.w = area.width;
00205 rect.h = area.height;
00206
00207 Uint32 color = SDL_MapRGBA(mTarget->format, mColor.r, mColor.g, mColor.b, mColor.a);
00208 SDL_FillRect(mTarget, &rect, color);
00209 }
00210 }
00211
00212 void SDLGraphics::drawPoint(int x, int y)
00213 {
00214 ClipRectangle top = mClipStack.top();
00215 x += top.xOffset;
00216 y += top.yOffset;
00217
00218 if(!top.isPointInRect(x,y))
00219 return;
00220
00221 if (mAlpha)
00222 {
00223 SDLputPixelAlpha(mTarget, x, y, mColor);
00224 }
00225 else
00226 {
00227 SDLputPixel(mTarget, x, y, mColor);
00228 }
00229 }
00230
00231 void SDLGraphics::drawHLine(int x1, int y, int x2)
00232 {
00233 ClipRectangle top = mClipStack.top();
00234 x1 += top.xOffset;
00235 y += top.yOffset;
00236 x2 += top.xOffset;
00237
00238 if (y < top.y || y >= top.y + top.height)
00239 return;
00240
00241 if (x1 > x2)
00242 {
00243 x1 ^= x2;
00244 x2 ^= x1;
00245 x1 ^= x2;
00246 }
00247
00248 if (top.x > x1)
00249 {
00250 if (top.x > x2)
00251 {
00252 return;
00253 }
00254 x1 = top.x;
00255 }
00256
00257 if (top.x + top.width <= x2)
00258 {
00259 if (top.x + top.width <= x1)
00260 {
00261 return;
00262 }
00263 x2 = top.x + top.width -1;
00264 }
00265
00266 int bpp = mTarget->format->BytesPerPixel;
00267
00268 SDL_LockSurface(mTarget);
00269
00270 Uint8 *p = (Uint8 *)mTarget->pixels + y * mTarget->pitch + x1 * bpp;
00271
00272 Uint32 pixel = SDL_MapRGB(mTarget->format, mColor.r, mColor.g, mColor.b);
00273
00274 switch(bpp) {
00275 case 1:
00276 {
00277 for (;x1 <= x2; ++x1)
00278 {
00279 *(p++) = pixel;
00280 }
00281 } break;
00282
00283 case 2:
00284 {
00285 Uint16* q = (Uint16*)p;
00286 for (;x1 <= x2; ++x1)
00287 {
00288 *(q++) = pixel;
00289 }
00290 } break;
00291
00292 case 3:
00293 {
00294 if(SDL_BYTEORDER == SDL_BIG_ENDIAN) {
00295 for (;x1 <= x2; ++x1)
00296 {
00297 p[0] = (pixel >> 16) & 0xff;
00298 p[1] = (pixel >> 8) & 0xff;
00299 p[2] = pixel & 0xff;
00300 p += 3;
00301 }
00302 }
00303 else
00304 {
00305 for (;x1 <= x2; ++x1)
00306 {
00307 p[0] = pixel & 0xff;
00308 p[1] = (pixel >> 8) & 0xff;
00309 p[2] = (pixel >> 16) & 0xff;
00310 p += 3;
00311 }
00312 }
00313 } break;
00314
00315 case 4:
00316 {
00317 Uint32* q = (Uint32*)p;
00318 for (;x1 <= x2; ++x1)
00319 {
00320 if (mAlpha)
00321 {
00322 *q = SDLAlpha32(pixel,*q,mColor.a);
00323 q++;
00324 }
00325 else
00326 {
00327 *(q++) = pixel;
00328 }
00329 }
00330 } break;
00331
00332 }
00333
00334 SDL_UnlockSurface(mTarget);
00335 }
00336
00337 void SDLGraphics::drawVLine(int x, int y1, int y2)
00338 {
00339 ClipRectangle top = mClipStack.top();
00340 x += top.xOffset;
00341 y1 += top.yOffset;
00342 y2 += top.yOffset;
00343
00344 if (x < top.x || x >= top.x + top.width)
00345 return;
00346
00347 if (y1 > y2)
00348 {
00349 y1 ^= y2;
00350 y2 ^= y1;
00351 y1 ^= y2;
00352 }
00353
00354 if (top.y > y1)
00355 {
00356 if (top.y > y2)
00357 {
00358 return;
00359 }
00360 y1 = top.y;
00361 }
00362
00363 if (top.y + top.height <= y2)
00364 {
00365 if (top.y + top.height <= y1)
00366 {
00367 return;
00368 }
00369 y2 = top.y + top.height - 1;
00370 }
00371
00372 int bpp = mTarget->format->BytesPerPixel;
00373
00374 SDL_LockSurface(mTarget);
00375
00376 Uint8 *p = (Uint8 *)mTarget->pixels + y1 * mTarget->pitch + x * bpp;
00377
00378 Uint32 pixel = SDL_MapRGB(mTarget->format, mColor.r, mColor.g, mColor.b);
00379
00380 switch(bpp) {
00381 case 1:
00382 {
00383 for (;y1 <= y2; ++y1)
00384 {
00385 *p = pixel;
00386 p += mTarget->pitch;
00387 }
00388 } break;
00389
00390 case 2:
00391 {
00392 for (;y1 <= y2; ++y1)
00393 {
00394 *(Uint16*)p = pixel;
00395 p += mTarget->pitch;
00396 }
00397 } break;
00398
00399 case 3:
00400 {
00401 if(SDL_BYTEORDER == SDL_BIG_ENDIAN) {
00402 for (;y1 <= y2; ++y1)
00403 {
00404 p[0] = (pixel >> 16) & 0xff;
00405 p[1] = (pixel >> 8) & 0xff;
00406 p[2] = pixel & 0xff;
00407 p += mTarget->pitch;
00408 }
00409 }
00410 else
00411 {
00412 for (;y1 <= y2; ++y1)
00413 {
00414 p[0] = pixel & 0xff;
00415 p[1] = (pixel >> 8) & 0xff;
00416 p[2] = (pixel >> 16) & 0xff;
00417 p += mTarget->pitch;
00418 }
00419 }
00420 } break;
00421
00422 case 4:
00423 {
00424 for (;y1 <= y2; ++y1)
00425 {
00426 if (mAlpha)
00427 {
00428 *(Uint32*)p = SDLAlpha32(pixel,*(Uint32*)p,mColor.a);
00429 }
00430 else
00431 {
00432 *(Uint32*)p = pixel;
00433 }
00434 p += mTarget->pitch;
00435 }
00436 } break;
00437 }
00438
00439 SDL_UnlockSurface(mTarget);
00440 }
00441
00442 void SDLGraphics::drawRectangle(const Rectangle& rectangle)
00443 {
00444 int x1 = rectangle.x;
00445 int x2 = rectangle.x + rectangle.width - 1;
00446 int y1 = rectangle.y;
00447 int y2 = rectangle.y + rectangle.height - 1;
00448
00449 drawHLine(x1, y1, x2);
00450 drawHLine(x1, y2, x2);
00451
00452 drawVLine(x1, y1, y2);
00453 drawVLine(x2, y1, y2);
00454 }
00455
00456 void SDLGraphics::drawLine(int x1, int y1, int x2, int y2)
00457 {
00458 if (x1 == x2)
00459 {
00460 drawVLine(x1, y1, y2);
00461 return;
00462 }
00463 if (y1 == y2)
00464 {
00465 drawHLine(x1, y1, x2);
00466 return;
00467 }
00468
00469 ClipRectangle top = mClipStack.top();
00470 x1 += top.xOffset;
00471 y1 += top.yOffset;
00472 x2 += top.xOffset;
00473 y2 += top.yOffset;
00474
00475
00476
00477 int dx = ABS(x2 - x1);
00478 int dy = ABS(y2 - y1);
00479
00480 if (dx > dy)
00481 {
00482 if (x1 > x2)
00483 {
00484
00485 x1 ^= x2;
00486 x2 ^= x1;
00487 x1 ^= x2;
00488
00489
00490 y1 ^= y2;
00491 y2 ^= y1;
00492 y1 ^= y2;
00493 }
00494
00495 if (y1 < y2)
00496 {
00497 int y = y1;
00498 int p = 0;
00499
00500 for (int x = x1; x <= x2; x++)
00501 {
00502 if (top.isPointInRect(x, y))
00503 {
00504 if (mAlpha)
00505 {
00506 SDLputPixelAlpha(mTarget, x, y, mColor);
00507 }
00508 else
00509 {
00510 SDLputPixel(mTarget, x, y, mColor);
00511 }
00512 }
00513
00514 p += dy;
00515
00516 if (p * 2 >= dx)
00517 {
00518 y++;
00519 p -= dx;
00520 }
00521 }
00522 }
00523 else
00524 {
00525 int y = y1;
00526 int p = 0;
00527
00528 for (int x = x1; x <= x2; x++)
00529 {
00530 if (top.isPointInRect(x, y))
00531 {
00532 if (mAlpha)
00533 {
00534 SDLputPixelAlpha(mTarget, x, y, mColor);
00535 }
00536 else
00537 {
00538 SDLputPixel(mTarget, x, y, mColor);
00539 }
00540 }
00541
00542 p += dy;
00543
00544 if (p * 2 >= dx)
00545 {
00546 y--;
00547 p -= dx;
00548 }
00549 }
00550 }
00551 }
00552 else
00553 {
00554 if (y1 > y2)
00555 {
00556
00557 y1 ^= y2;
00558 y2 ^= y1;
00559 y1 ^= y2;
00560
00561
00562 x1 ^= x2;
00563 x2 ^= x1;
00564 x1 ^= x2;
00565 }
00566
00567 if (x1 < x2)
00568 {
00569 int x = x1;
00570 int p = 0;
00571
00572 for (int y = y1; y <= y2; y++)
00573 {
00574 if (top.isPointInRect(x, y))
00575 {
00576 if (mAlpha)
00577 {
00578 SDLputPixelAlpha(mTarget, x, y, mColor);
00579 }
00580 else
00581 {
00582 SDLputPixel(mTarget, x, y, mColor);
00583 }
00584 }
00585
00586 p += dx;
00587
00588 if (p * 2 >= dy)
00589 {
00590 x++;
00591 p -= dy;
00592 }
00593 }
00594 }
00595 else
00596 {
00597 int x = x1;
00598 int p = 0;
00599
00600 for (int y = y1; y <= y2; y++)
00601 {
00602 if (top.isPointInRect(x, y))
00603 {
00604 if (mAlpha)
00605 {
00606 SDLputPixelAlpha(mTarget, x, y, mColor);
00607 }
00608 else
00609 {
00610 SDLputPixel(mTarget, x, y, mColor);
00611 }
00612 }
00613
00614 p += dx;
00615
00616 if (p * 2 >= dy)
00617 {
00618 x--;
00619 p -= dy;
00620 }
00621 }
00622 }
00623 }
00624 }
00625
00626 void SDLGraphics::setColor(const Color& color)
00627 {
00628 mColor = color;
00629
00630 mAlpha = color.a != 255;
00631 }
00632
00633 const Color& SDLGraphics::getColor()
00634 {
00635 return mColor;
00636 }
00637
00638 void SDLGraphics::drawSDLSurface(SDL_Surface* surface, SDL_Rect source,
00639 SDL_Rect destination)
00640 {
00641 ClipRectangle top = mClipStack.top();
00642 destination.x += top.xOffset;
00643 destination.y += top.yOffset;
00644
00645 SDL_BlitSurface(surface, &source, mTarget, &destination);
00646 }
00647 }