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 }