Mercurial > fife-parpg
comparison ext/guichan-0.8.2/src/sdl/sdlgraphics.cpp @ 378:64738befdf3b
bringing in the changes from the build_system_rework branch in preparation for the 0.3.0 release. This commit will require the Jan2010 devkit. Clients will also need to be modified to the new way to import fife.
author | vtchill@33b003aa-7bff-0310-803a-e67f0ece8222 |
---|---|
date | Mon, 11 Jan 2010 23:34:52 +0000 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
377:fe6fb0e0ed23 | 378:64738befdf3b |
---|---|
1 /* _______ __ __ __ ______ __ __ _______ __ __ | |
2 * / _____/\ / /\ / /\ / /\ / ____/\ / /\ / /\ / ___ /\ / |\/ /\ | |
3 * / /\____\// / // / // / // /\___\// /_// / // /\_/ / // , |/ / / | |
4 * / / /__ / / // / // / // / / / ___ / // ___ / // /| ' / / | |
5 * / /_// /\ / /_// / // / // /_/_ / / // / // /\_/ / // / | / / | |
6 * /______/ //______/ //_/ //_____/\ /_/ //_/ //_/ //_/ //_/ /|_/ / | |
7 * \______\/ \______\/ \_\/ \_____\/ \_\/ \_\/ \_\/ \_\/ \_\/ \_\/ | |
8 * | |
9 * Copyright (c) 2004 - 2008 Olof Naessén and Per Larsson | |
10 * | |
11 * | |
12 * Per Larsson a.k.a finalman | |
13 * Olof Naessén a.k.a jansem/yakslem | |
14 * | |
15 * Visit: http://guichan.sourceforge.net | |
16 * | |
17 * License: (BSD) | |
18 * Redistribution and use in source and binary forms, with or without | |
19 * modification, are permitted provided that the following conditions | |
20 * are met: | |
21 * 1. Redistributions of source code must retain the above copyright | |
22 * notice, this list of conditions and the following disclaimer. | |
23 * 2. Redistributions in binary form must reproduce the above copyright | |
24 * notice, this list of conditions and the following disclaimer in | |
25 * the documentation and/or other materials provided with the | |
26 * distribution. | |
27 * 3. Neither the name of Guichan nor the names of its contributors may | |
28 * be used to endorse or promote products derived from this software | |
29 * without specific prior written permission. | |
30 * | |
31 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | |
32 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | |
33 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | |
34 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | |
35 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | |
36 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED | |
37 * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR | |
38 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF | |
39 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING | |
40 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | |
41 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
42 */ | |
43 | |
44 /* | |
45 * For comments regarding functions please see the header file. | |
46 */ | |
47 | |
48 #include "guichan/sdl/sdlgraphics.hpp" | |
49 | |
50 #include "guichan/exception.hpp" | |
51 #include "guichan/font.hpp" | |
52 #include "guichan/image.hpp" | |
53 #include "guichan/sdl/sdlimage.hpp" | |
54 #include "guichan/sdl/sdlpixel.hpp" | |
55 | |
56 // For some reason an old version of MSVC did not like std::abs, | |
57 // so we added this macro. | |
58 #ifndef ABS | |
59 #define ABS(x) ((x)<0?-(x):(x)) | |
60 #endif | |
61 | |
62 namespace gcn | |
63 { | |
64 | |
65 SDLGraphics::SDLGraphics() | |
66 { | |
67 mAlpha = false; | |
68 } | |
69 | |
70 void SDLGraphics::_beginDraw() | |
71 { | |
72 Rectangle area; | |
73 area.x = 0; | |
74 area.y = 0; | |
75 area.width = mTarget->w; | |
76 area.height = mTarget->h; | |
77 pushClipArea(area); | |
78 } | |
79 | |
80 void SDLGraphics::_endDraw() | |
81 { | |
82 popClipArea(); | |
83 } | |
84 | |
85 void SDLGraphics::setTarget(SDL_Surface* target) | |
86 { | |
87 mTarget = target; | |
88 } | |
89 | |
90 bool SDLGraphics::pushClipArea(Rectangle area) | |
91 { | |
92 SDL_Rect rect; | |
93 bool result = Graphics::pushClipArea(area); | |
94 | |
95 const ClipRectangle& carea = mClipStack.top(); | |
96 rect.x = carea.x; | |
97 rect.y = carea.y; | |
98 rect.w = carea.width; | |
99 rect.h = carea.height; | |
100 | |
101 SDL_SetClipRect(mTarget, &rect); | |
102 | |
103 return result; | |
104 } | |
105 | |
106 void SDLGraphics::popClipArea() | |
107 { | |
108 Graphics::popClipArea(); | |
109 | |
110 if (mClipStack.empty()) | |
111 { | |
112 return; | |
113 } | |
114 | |
115 const ClipRectangle& carea = mClipStack.top(); | |
116 SDL_Rect rect; | |
117 rect.x = carea.x; | |
118 rect.y = carea.y; | |
119 rect.w = carea.width; | |
120 rect.h = carea.height; | |
121 | |
122 SDL_SetClipRect(mTarget, &rect); | |
123 } | |
124 | |
125 SDL_Surface* SDLGraphics::getTarget() const | |
126 { | |
127 return mTarget; | |
128 } | |
129 | |
130 void SDLGraphics::drawImage(const Image* image, | |
131 int srcX, | |
132 int srcY, | |
133 int dstX, | |
134 int dstY, | |
135 int width, | |
136 int height) | |
137 { | |
138 if (mClipStack.empty()) | |
139 { | |
140 throw GCN_EXCEPTION("Clip stack is empty, perhaps you called a draw funtion outside of _beginDraw() and _endDraw()?"); | |
141 } | |
142 | |
143 const ClipRectangle& top = mClipStack.top(); | |
144 | |
145 SDL_Rect src; | |
146 SDL_Rect dst; | |
147 src.x = srcX; | |
148 src.y = srcY; | |
149 src.w = width; | |
150 src.h = height; | |
151 dst.x = dstX + top.xOffset; | |
152 dst.y = dstY + top.yOffset; | |
153 | |
154 const SDLImage* srcImage = dynamic_cast<const SDLImage*>(image); | |
155 | |
156 if (srcImage == NULL) | |
157 { | |
158 throw GCN_EXCEPTION("Trying to draw an image of unknown format, must be an SDLImage."); | |
159 } | |
160 | |
161 SDL_BlitSurface(srcImage->getSurface(), &src, mTarget, &dst); | |
162 } | |
163 | |
164 void SDLGraphics::fillRectangle(const Rectangle& rectangle) | |
165 { | |
166 if (mClipStack.empty()) | |
167 { | |
168 throw GCN_EXCEPTION("Clip stack is empty, perhaps you called a draw funtion outside of _beginDraw() and _endDraw()?"); | |
169 } | |
170 | |
171 const ClipRectangle& top = mClipStack.top(); | |
172 | |
173 Rectangle area = rectangle; | |
174 area.x += top.xOffset; | |
175 area.y += top.yOffset; | |
176 | |
177 if(!area.isIntersecting(top)) | |
178 { | |
179 return; | |
180 } | |
181 | |
182 if (mAlpha) | |
183 { | |
184 int x1 = area.x > top.x ? area.x : top.x; | |
185 int y1 = area.y > top.y ? area.y : top.y; | |
186 int x2 = area.x + area.width < top.x + top.width ? area.x + area.width : top.x + top.width; | |
187 int y2 = area.y + area.height < top.y + top.height ? area.y + area.height : top.y + top.height; | |
188 int x, y; | |
189 | |
190 SDL_LockSurface(mTarget); | |
191 for (y = y1; y < y2; y++) | |
192 { | |
193 for (x = x1; x < x2; x++) | |
194 { | |
195 SDLputPixelAlpha(mTarget, x, y, mColor); | |
196 } | |
197 } | |
198 SDL_UnlockSurface(mTarget); | |
199 | |
200 } | |
201 else | |
202 { | |
203 SDL_Rect rect; | |
204 rect.x = area.x; | |
205 rect.y = area.y; | |
206 rect.w = area.width; | |
207 rect.h = area.height; | |
208 | |
209 Uint32 color = SDL_MapRGBA(mTarget->format, | |
210 mColor.r, | |
211 mColor.g, | |
212 mColor.b, | |
213 mColor.a); | |
214 SDL_FillRect(mTarget, &rect, color); | |
215 } | |
216 } | |
217 | |
218 void SDLGraphics::drawPoint(int x, int y) | |
219 { | |
220 if (mClipStack.empty()) | |
221 { | |
222 throw GCN_EXCEPTION("Clip stack is empty, perhaps you called a draw funtion outside of _beginDraw() and _endDraw()?"); | |
223 } | |
224 | |
225 const ClipRectangle& top = mClipStack.top(); | |
226 | |
227 x += top.xOffset; | |
228 y += top.yOffset; | |
229 | |
230 if(!top.isPointInRect(x,y)) | |
231 return; | |
232 | |
233 if (mAlpha) | |
234 { | |
235 SDLputPixelAlpha(mTarget, x, y, mColor); | |
236 } | |
237 else | |
238 { | |
239 SDLputPixel(mTarget, x, y, mColor); | |
240 } | |
241 } | |
242 | |
243 void SDLGraphics::drawHLine(int x1, int y, int x2) | |
244 { | |
245 if (mClipStack.empty()) | |
246 { | |
247 throw GCN_EXCEPTION("Clip stack is empty, perhaps you called a draw funtion outside of _beginDraw() and _endDraw()?"); | |
248 } | |
249 | |
250 const ClipRectangle& top = mClipStack.top(); | |
251 | |
252 x1 += top.xOffset; | |
253 y += top.yOffset; | |
254 x2 += top.xOffset; | |
255 | |
256 if (y < top.y || y >= top.y + top.height) | |
257 { | |
258 return; | |
259 } | |
260 | |
261 if (x1 > x2) | |
262 { | |
263 x1 ^= x2; | |
264 x2 ^= x1; | |
265 x1 ^= x2; | |
266 } | |
267 | |
268 if (top.x > x1) | |
269 { | |
270 if (top.x > x2) | |
271 { | |
272 return; | |
273 } | |
274 | |
275 x1 = top.x; | |
276 } | |
277 | |
278 if (top.x + top.width <= x2) | |
279 { | |
280 if (top.x + top.width <= x1) | |
281 { | |
282 return; | |
283 } | |
284 | |
285 x2 = top.x + top.width -1; | |
286 } | |
287 | |
288 int bpp = mTarget->format->BytesPerPixel; | |
289 | |
290 SDL_LockSurface(mTarget); | |
291 | |
292 Uint8 *p = (Uint8 *)mTarget->pixels + y * mTarget->pitch + x1 * bpp; | |
293 | |
294 Uint32 pixel = SDL_MapRGB(mTarget->format, | |
295 mColor.r, | |
296 mColor.g, | |
297 mColor.b); | |
298 switch(bpp) | |
299 { | |
300 case 1: | |
301 for (;x1 <= x2; ++x1) | |
302 { | |
303 *(p++) = pixel; | |
304 } | |
305 break; | |
306 | |
307 case 2: | |
308 { | |
309 Uint16* q = (Uint16*)p; | |
310 for (;x1 <= x2; ++x1) | |
311 { | |
312 *(q++) = pixel; | |
313 } | |
314 break; | |
315 } | |
316 case 3: | |
317 if(SDL_BYTEORDER == SDL_BIG_ENDIAN) | |
318 { | |
319 for (;x1 <= x2; ++x1) | |
320 { | |
321 p[0] = (pixel >> 16) & 0xff; | |
322 p[1] = (pixel >> 8) & 0xff; | |
323 p[2] = pixel & 0xff; | |
324 p += 3; | |
325 } | |
326 } | |
327 else | |
328 { | |
329 for (;x1 <= x2; ++x1) | |
330 { | |
331 p[0] = pixel & 0xff; | |
332 p[1] = (pixel >> 8) & 0xff; | |
333 p[2] = (pixel >> 16) & 0xff; | |
334 p += 3; | |
335 } | |
336 } | |
337 break; | |
338 | |
339 case 4: | |
340 { | |
341 Uint32* q = (Uint32*)p; | |
342 for (;x1 <= x2; ++x1) | |
343 { | |
344 if (mAlpha) | |
345 { | |
346 *q = SDLAlpha32(pixel,*q,mColor.a); | |
347 q++; | |
348 } | |
349 else | |
350 { | |
351 *(q++) = pixel; | |
352 } | |
353 } | |
354 break; | |
355 } | |
356 | |
357 } // end switch | |
358 | |
359 SDL_UnlockSurface(mTarget); | |
360 } | |
361 | |
362 void SDLGraphics::drawVLine(int x, int y1, int y2) | |
363 { | |
364 if (mClipStack.empty()) | |
365 { | |
366 throw GCN_EXCEPTION("Clip stack is empty, perhaps you called a draw funtion outside of _beginDraw() and _endDraw()?"); | |
367 } | |
368 | |
369 const ClipRectangle& top = mClipStack.top(); | |
370 | |
371 x += top.xOffset; | |
372 y1 += top.yOffset; | |
373 y2 += top.yOffset; | |
374 | |
375 if (x < top.x || x >= top.x + top.width) | |
376 { | |
377 return; | |
378 } | |
379 | |
380 if (y1 > y2) | |
381 { | |
382 y1 ^= y2; | |
383 y2 ^= y1; | |
384 y1 ^= y2; | |
385 } | |
386 | |
387 if (top.y > y1) | |
388 { | |
389 if (top.y > y2) | |
390 { | |
391 return; | |
392 } | |
393 | |
394 y1 = top.y; | |
395 } | |
396 | |
397 if (top.y + top.height <= y2) | |
398 { | |
399 if (top.y + top.height <= y1) | |
400 { | |
401 return; | |
402 } | |
403 | |
404 y2 = top.y + top.height - 1; | |
405 } | |
406 | |
407 int bpp = mTarget->format->BytesPerPixel; | |
408 | |
409 SDL_LockSurface(mTarget); | |
410 | |
411 Uint8 *p = (Uint8 *)mTarget->pixels + y1 * mTarget->pitch + x * bpp; | |
412 | |
413 Uint32 pixel = SDL_MapRGB(mTarget->format, mColor.r, mColor.g, mColor.b); | |
414 | |
415 switch(bpp) | |
416 { | |
417 case 1: | |
418 for (;y1 <= y2; ++y1) | |
419 { | |
420 *p = pixel; | |
421 p += mTarget->pitch; | |
422 } | |
423 break; | |
424 | |
425 case 2: | |
426 for (;y1 <= y2; ++y1) | |
427 { | |
428 *(Uint16*)p = pixel; | |
429 p += mTarget->pitch; | |
430 } | |
431 break; | |
432 | |
433 case 3: | |
434 if(SDL_BYTEORDER == SDL_BIG_ENDIAN) | |
435 { | |
436 for (;y1 <= y2; ++y1) | |
437 { | |
438 p[0] = (pixel >> 16) & 0xff; | |
439 p[1] = (pixel >> 8) & 0xff; | |
440 p[2] = pixel & 0xff; | |
441 p += mTarget->pitch; | |
442 } | |
443 } | |
444 else | |
445 { | |
446 for (;y1 <= y2; ++y1) | |
447 { | |
448 p[0] = pixel & 0xff; | |
449 p[1] = (pixel >> 8) & 0xff; | |
450 p[2] = (pixel >> 16) & 0xff; | |
451 p += mTarget->pitch; | |
452 } | |
453 } | |
454 break; | |
455 | |
456 case 4: | |
457 for (;y1 <= y2; ++y1) | |
458 { | |
459 if (mAlpha) | |
460 { | |
461 *(Uint32*)p = SDLAlpha32(pixel,*(Uint32*)p,mColor.a); | |
462 } | |
463 else | |
464 { | |
465 *(Uint32*)p = pixel; | |
466 } | |
467 p += mTarget->pitch; | |
468 } | |
469 break; | |
470 | |
471 } // end switch | |
472 | |
473 SDL_UnlockSurface(mTarget); | |
474 } | |
475 | |
476 void SDLGraphics::drawRectangle(const Rectangle& rectangle) | |
477 { | |
478 int x1 = rectangle.x; | |
479 int x2 = rectangle.x + rectangle.width - 1; | |
480 int y1 = rectangle.y; | |
481 int y2 = rectangle.y + rectangle.height - 1; | |
482 | |
483 drawHLine(x1, y1, x2); | |
484 drawHLine(x1, y2, x2); | |
485 | |
486 drawVLine(x1, y1, y2); | |
487 drawVLine(x2, y1, y2); | |
488 } | |
489 | |
490 void SDLGraphics::drawLine(int x1, int y1, int x2, int y2) | |
491 { | |
492 if (x1 == x2) | |
493 { | |
494 drawVLine(x1, y1, y2); | |
495 return; | |
496 } | |
497 if (y1 == y2) | |
498 { | |
499 drawHLine(x1, y1, x2); | |
500 return; | |
501 } | |
502 | |
503 if (mClipStack.empty()) | |
504 { | |
505 throw GCN_EXCEPTION("Clip stack is empty, perhaps you called a draw funtion outside of _beginDraw() and _endDraw()?"); | |
506 } | |
507 | |
508 const ClipRectangle& top = mClipStack.top(); | |
509 | |
510 x1 += top.xOffset; | |
511 y1 += top.yOffset; | |
512 x2 += top.xOffset; | |
513 y2 += top.yOffset; | |
514 | |
515 // Draw a line with Bresenham | |
516 | |
517 int dx = ABS(x2 - x1); | |
518 int dy = ABS(y2 - y1); | |
519 | |
520 if (dx > dy) | |
521 { | |
522 if (x1 > x2) | |
523 { | |
524 // swap x1, x2 | |
525 x1 ^= x2; | |
526 x2 ^= x1; | |
527 x1 ^= x2; | |
528 | |
529 // swap y1, y2 | |
530 y1 ^= y2; | |
531 y2 ^= y1; | |
532 y1 ^= y2; | |
533 } | |
534 | |
535 if (y1 < y2) | |
536 { | |
537 int y = y1; | |
538 int p = 0; | |
539 | |
540 for (int x = x1; x <= x2; x++) | |
541 { | |
542 if (top.isPointInRect(x, y)) | |
543 { | |
544 if (mAlpha) | |
545 { | |
546 SDLputPixelAlpha(mTarget, x, y, mColor); | |
547 } | |
548 else | |
549 { | |
550 SDLputPixel(mTarget, x, y, mColor); | |
551 } | |
552 } | |
553 | |
554 p += dy; | |
555 | |
556 if (p * 2 >= dx) | |
557 { | |
558 y++; | |
559 p -= dx; | |
560 } | |
561 } | |
562 } | |
563 else | |
564 { | |
565 int y = y1; | |
566 int p = 0; | |
567 | |
568 for (int x = x1; x <= x2; x++) | |
569 { | |
570 if (top.isPointInRect(x, y)) | |
571 { | |
572 if (mAlpha) | |
573 { | |
574 SDLputPixelAlpha(mTarget, x, y, mColor); | |
575 } | |
576 else | |
577 { | |
578 SDLputPixel(mTarget, x, y, mColor); | |
579 } | |
580 } | |
581 | |
582 p += dy; | |
583 | |
584 if (p * 2 >= dx) | |
585 { | |
586 y--; | |
587 p -= dx; | |
588 } | |
589 } | |
590 } | |
591 } | |
592 else | |
593 { | |
594 if (y1 > y2) | |
595 { | |
596 // swap y1, y2 | |
597 y1 ^= y2; | |
598 y2 ^= y1; | |
599 y1 ^= y2; | |
600 | |
601 // swap x1, x2 | |
602 x1 ^= x2; | |
603 x2 ^= x1; | |
604 x1 ^= x2; | |
605 } | |
606 | |
607 if (x1 < x2) | |
608 { | |
609 int x = x1; | |
610 int p = 0; | |
611 | |
612 for (int y = y1; y <= y2; y++) | |
613 { | |
614 if (top.isPointInRect(x, y)) | |
615 { | |
616 if (mAlpha) | |
617 { | |
618 SDLputPixelAlpha(mTarget, x, y, mColor); | |
619 } | |
620 else | |
621 { | |
622 SDLputPixel(mTarget, x, y, mColor); | |
623 } | |
624 } | |
625 | |
626 p += dx; | |
627 | |
628 if (p * 2 >= dy) | |
629 { | |
630 x++; | |
631 p -= dy; | |
632 } | |
633 } | |
634 } | |
635 else | |
636 { | |
637 int x = x1; | |
638 int p = 0; | |
639 | |
640 for (int y = y1; y <= y2; y++) | |
641 { | |
642 if (top.isPointInRect(x, y)) | |
643 { | |
644 if (mAlpha) | |
645 { | |
646 SDLputPixelAlpha(mTarget, x, y, mColor); | |
647 } | |
648 else | |
649 { | |
650 SDLputPixel(mTarget, x, y, mColor); | |
651 } | |
652 } | |
653 | |
654 p += dx; | |
655 | |
656 if (p * 2 >= dy) | |
657 { | |
658 x--; | |
659 p -= dy; | |
660 } | |
661 } | |
662 } | |
663 } | |
664 } | |
665 | |
666 void SDLGraphics::setColor(const Color& color) | |
667 { | |
668 mColor = color; | |
669 | |
670 mAlpha = color.a != 255; | |
671 } | |
672 | |
673 const Color& SDLGraphics::getColor() const | |
674 { | |
675 return mColor; | |
676 } | |
677 | |
678 void SDLGraphics::drawSDLSurface(SDL_Surface* surface, | |
679 SDL_Rect source, | |
680 SDL_Rect destination) | |
681 { | |
682 if (mClipStack.empty()) | |
683 { | |
684 throw GCN_EXCEPTION("Clip stack is empty, perhaps you called a draw funtion outside of _beginDraw() and _endDraw()?"); | |
685 } | |
686 | |
687 const ClipRectangle& top = mClipStack.top(); | |
688 | |
689 destination.x += top.xOffset; | |
690 destination.y += top.yOffset; | |
691 | |
692 SDL_BlitSurface(surface, &source, mTarget, &destination); | |
693 } | |
694 } |