624bd3ecf23d3641f8678cd3c51835bc908f4a68
[supertux.git] / src / unison / src / video / Blitters.cpp
1 //          Copyright Timothy Goya 2007.
2 // Distributed under the Boost Software License, Version 1.0.
3 //    (See accompanying file LICENSE_1_0.txt or copy at
4 //          http://www.boost.org/LICENSE_1_0.txt)
5
6 #include <unison/video/Blitters.hpp>
7 #include <unison/video/Surface.hpp>
8
9 #include <assert.h>
10
11 namespace Unison
12 {
13    namespace Video
14    {
15       void Blitters::blit_upper(const Surface &src, Rect src_rect, Surface &dst, Point dst_pos, void (*blit_lower)(const Surface &, const Rect &, Surface &, const Point &))
16       {
17          assert(src.get_pixels());
18          assert(dst.get_pixels());
19          assert(blit_lower);
20          if(src_rect == Rect())
21          {
22             src_rect.size.x = src.get_size().x;
23             src_rect.size.y = src.get_size().y;
24          }
25          if(dst_pos.x < 0)
26          {
27             if(src_rect.size.x < (unsigned int) -dst_pos.x)
28             {
29                return;
30             }
31             src_rect.pos.x += -dst_pos.x;
32             src_rect.size.x += dst_pos.x;
33             dst_pos.x = 0;
34          }
35          if(dst_pos.y < 0)
36          {
37             if(src_rect.size.y < (unsigned int) -dst_pos.y)
38             {
39                return;
40             }
41             src_rect.pos.y += -dst_pos.y;
42             src_rect.size.y += dst_pos.y;
43             dst_pos.y = 0;
44          }
45          if(src_rect.pos.x < 0)
46          {
47             if(src_rect.size.x < (unsigned int) -src_rect.pos.x)
48             {
49                return;
50             }
51             src_rect.size.x += src_rect.pos.x;
52             src_rect.pos.x = 0;
53          }
54          if(src_rect.pos.y < 0)
55          {
56             if(src_rect.size.y < (unsigned int) -src_rect.pos.y)
57             {
58                return;
59             }
60             src_rect.size.y += src_rect.pos.y;
61             src_rect.pos.y = 0;
62          }
63          if(src_rect.get_right() > (int) src.get_size().x)
64          {
65             src_rect.size.x = src.get_size().x - src_rect.pos.x;
66          }
67          if(src_rect.get_bottom() > (int) src.get_size().y)
68          {
69             src_rect.size.y = src.get_size().y - src_rect.pos.y;
70          }
71          if(dst_pos.x + src_rect.size.x > dst.get_size().x)
72          {
73             src_rect.size.x = dst.get_size().x - dst_pos.x;
74          }
75          if(dst_pos.y + src_rect.size.y > dst.get_size().y)
76          {
77             src_rect.size.y = dst.get_size().y - dst_pos.y;
78          }
79          blit_lower(src, src_rect, dst, dst_pos);
80       }
81
82       void Blitters::blit_lower_none(const Surface &src, const Rect &src_rect, Surface &dst, const Point &dst_pos)
83       {
84          if(src_rect.pos == Point() && dst_pos == Point() && src.get_size().x == dst.get_size().x && src_rect.size.x == dst.get_size().x)
85          {
86             memcpy(dst.get_pixels(), src.get_pixels(), src_rect.size.x * src_rect.size.y * sizeof(Color));
87          }
88          else
89          {
90             const Color *src_line = src.get_pixels() + src_rect.pos.y * src.get_size().x + src_rect.pos.x;
91             Color *dst_line = dst.get_pixels() + dst_pos.y * dst.get_size().x + dst_pos.x;
92             for(unsigned int y = 0;y < src_rect.size.y;y++)
93             {
94                memcpy(dst_line, src_line, src_rect.size.x * sizeof(Color));
95                src_line += src.get_size().x;
96                dst_line += dst.get_size().x;
97             }
98          }
99       }
100
101       void Blitters::blit_lower_mask(const Surface &src, const Rect &src_rect, Surface &dst, const Point &dst_pos)
102       {
103          const Color *src_pixel = src.get_pixels() + src_rect.pos.y * src.get_size().x + src_rect.pos.x;
104          Color *dst_pixel = dst.get_pixels() + dst_pos.y * dst.get_size().x + dst_pos.x;
105          for(unsigned int y = 0;y < src_rect.size.y;y++)
106          {
107             for(unsigned int x = 0;x < src_rect.size.x;x++)
108             {
109                if(src_pixel->alpha)
110                {
111                   *dst_pixel = *src_pixel;
112                }
113                src_pixel++;
114                dst_pixel++;
115             }
116             src_pixel += src.get_size().x - src_rect.size.x;
117             dst_pixel += dst.get_size().x - src_rect.size.x;
118          }
119       }
120
121       void Blitters::blit_lower_alpha(const Surface &src, const Rect &src_rect, Surface &dst, const Point &dst_pos)
122       {
123          const Color *src_pixel = src.get_pixels() + src_rect.pos.y * src.get_size().x + src_rect.pos.x;
124          Color *dst_pixel = dst.get_pixels() + dst_pos.y * dst.get_size().x + dst_pos.x;
125          for(unsigned int y = 0;y < src_rect.size.y;y++)
126          {
127             for(unsigned int x = 0;x < src_rect.size.x;x++)
128             {
129                dst_pixel->red += src_pixel->red * src_pixel->alpha - dst_pixel->red * src_pixel->alpha;
130                dst_pixel->green += src_pixel->green * src_pixel->alpha - dst_pixel->green * src_pixel->alpha;
131                dst_pixel->blue += src_pixel->blue * src_pixel->alpha - dst_pixel->green * src_pixel->blue;
132                src_pixel++;
133                dst_pixel++;
134             }
135             src_pixel += src.get_size().x - src_rect.size.x;
136             dst_pixel += dst.get_size().x - src_rect.size.x;
137          }
138       }
139
140       void Blitters::blit_lower_add(const Surface &src, const Rect &src_rect, Surface &dst, const Point &dst_pos)
141       {
142          const Color *src_pixel = src.get_pixels() + src_rect.pos.y * src.get_size().x + src_rect.pos.x;
143          Color *dst_pixel = dst.get_pixels() + dst_pos.y * dst.get_size().x + dst_pos.x;
144          for(unsigned int y = 0;y < src_rect.size.y;y++)
145          {
146             for(unsigned int x = 0;x < src_rect.size.x;x++)
147             {
148                if(src_pixel->red != 0 && dst_pixel->red != 0xff)
149                {
150                   int redsum = dst_pixel->red + src_pixel->red * src_pixel->alpha / 0xff;
151                   dst_pixel->red = redsum & ~0xff ? 0xff : redsum;
152                }
153                if(src_pixel->green != 0 && dst_pixel->green != 0xff)
154                {
155                   int greensum = dst_pixel->green + src_pixel->green * src_pixel->alpha / 0xff;
156                   dst_pixel->green = greensum & ~0xff ? 0xff : greensum;
157                }
158                if(src_pixel->blue != 0 && dst_pixel->blue != 0xff)
159                {
160                   int bluesum = dst_pixel->blue + src_pixel->blue * src_pixel->alpha / 0xff;
161                   dst_pixel->blue = bluesum & ~0xff ? 0xff : bluesum;
162                }
163                src_pixel++;
164                dst_pixel++;
165             }
166             src_pixel += src.get_size().x - src_rect.size.x;
167             dst_pixel += dst.get_size().x - src_rect.size.x;
168          }
169       }
170
171       void Blitters::blit_lower_mod(const Surface &src, const Rect &src_rect, Surface &dst, const Point &dst_pos)
172       {
173          const Color *src_pixel = src.get_pixels() + src_rect.pos.y * src.get_size().x + src_rect.pos.x;
174          Color *dst_pixel = dst.get_pixels() + dst_pos.y * dst.get_size().x + dst_pos.x;
175          for(unsigned int y = 0;y < src_rect.size.y;y++)
176          {
177             for(unsigned int x = 0;x < src_rect.size.x;x++)
178             {
179                dst_pixel->red = dst_pixel->red * src_pixel->red / 0xff;
180                dst_pixel->green = dst_pixel->green * src_pixel->green / 0xff;
181                dst_pixel->blue = dst_pixel->blue * src_pixel->blue / 0xff;
182                dst_pixel->alpha = dst_pixel->alpha * src_pixel->alpha / 0xff;
183                src_pixel++;
184                dst_pixel++;
185             }
186             src_pixel += src.get_size().x - src_rect.size.x;
187             dst_pixel += dst.get_size().x - src_rect.size.x;
188          }
189       }
190    }
191 }