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