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