comparison ext/guichan-0.8.1/src/sdl/sdlgraphics.cpp @ 0:4a0efb7baf70

* Datasets becomes the new trunk and retires after that :-)
author mvbarracuda@33b003aa-7bff-0310-803a-e67f0ece8222
date Sun, 29 Jun 2008 18:44:17 +0000
parents
children
comparison
equal deleted inserted replaced
-1:000000000000 0:4a0efb7baf70
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 }