Initial integration, lots of broken stuff
[supertux.git] / src / unison / src / video / Surface.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/Texture.hpp>
7 #include <unison/video/Window.hpp>
8 #include <unison/video/Renderers.hpp>
9 #include <unison/video/Color.hpp>
10 #include <unison/video/sdl/Blitters.hpp>
11 #include <unison/video/backend/Renderer.hpp>
12 #include <unison/video/backend/Texture.hpp>
13 #include <unison/vfs/stream.hpp>
14
15 #include <assert.h>
16
17 namespace Unison
18 {
19    namespace Video
20    {
21       Surface::Surface() :
22          pixels(0)
23       {
24       }
25
26       Surface::Surface(const std::string &filename) :
27          pixels(0)
28       {
29          *this = Renderers::get().get_renderer().load_surface(filename);
30       }
31
32       Surface::Surface(const std::string &filename, const Color &colorkey) :
33          pixels(0)
34       {
35          *this = Renderers::get().get_renderer().load_surface(filename, colorkey);
36       }
37
38       Surface::Surface(const Area &size) :
39          pixels(new PixelBuffer(size))
40       {
41          //fill(Color::WHITE);
42       }
43
44       Surface::Surface(const Surface &rhs) :
45          Blittable(),
46          pixels(rhs.pixels)
47       {
48          if(pixels)
49          {
50             pixels->ref();
51          }
52       }
53
54       Surface::~Surface()
55       {
56          if(pixels)
57          {
58             pixels->unref();
59          }
60       }
61
62       Surface &Surface::operator =(const Surface &rhs)
63       {
64          if(rhs.pixels)
65          {
66             rhs.pixels->ref();
67          }
68          if(pixels)
69          {
70             pixels->unref();
71          }
72          pixels = rhs.pixels;
73          return *this;
74       }
75
76       void Surface::save(const std::string &filename) const
77       {
78          Renderers::get().get_renderer().save_surface(*this, filename);
79       }
80
81       void Surface::blit(const Surface &src, const Point &dst_pos, const Rect &src_rect, const RenderOptions &options)
82       {
83          cow();
84          assert(pixels);
85          Renderers::get().get_renderer().blit(src, src_rect, *this, dst_pos, options);
86       }
87
88       void Surface::blit(const Texture &src, const Point &dst_pos, const Rect &src_rect, const RenderOptions &options)
89       {
90          cow();
91          assert(pixels);
92          Renderers::get().get_renderer().blit(Backend::Texture::get_texture(src.get_id()), src_rect, *this, dst_pos, options);
93       }
94
95       void Surface::fill(const Color &color, const Rect &rect)
96       {
97          cow();
98          assert(pixels);
99          Renderers::get().get_renderer().fill(*this, color, rect);
100       }
101
102       void Surface::fill_blend(const Color &color, const Rect &rect)
103       {
104          cow();
105          assert(pixels);
106          Renderers::get().get_renderer().fill_blend(*this, color, rect);
107       }
108
109       namespace
110       {
111          Color merge(const Color &color0, const Color &color1, int rem, int total)
112          {
113             return Color((color0.red * (total - rem) + color1.red * rem) / total,
114                          (color0.green * (total - rem) + color1.green * rem) / total,
115                          (color0.blue * (total - rem) + color1.blue * rem) / total,
116                          (color0.alpha * (total - rem) + color1.alpha * rem) / total);
117          }
118       }
119
120       Surface Surface::scale(unsigned int numerator, unsigned int denominator) const
121       {
122          assert(pixels);
123          if(numerator == denominator)
124          {
125             return *this;
126          }
127          else
128          {
129             Surface scaled(get_size() * numerator / denominator);
130             for(unsigned int y = 0;y < scaled.get_size().y;y++)
131             {
132                for(unsigned int x = 0;x < scaled.get_size().x;x++)
133                {
134                   unsigned int srcx = x * denominator / numerator;
135                   unsigned int srcy = y * denominator / numerator;
136                   //scaled.set_pixel(Point(x, y), get_pixel(Point(srcx, srcy)));
137                   int incx = (srcx + 1 == get_size().x ? 0 : 1);
138                   int incy = (srcy + 1 == get_size().y ? 0 : 1);
139                   Color color00 = get_pixel(srcx, srcy);
140                   Color color01 = get_pixel(srcx + incx, srcy);
141                   Color color10 = get_pixel(srcx, srcy + incy);
142                   Color color11 = get_pixel(srcx + incx, srcy + incy);
143                   int remx = x * denominator % numerator;
144                   Color color0 = merge(color00, color01, remx, numerator);
145                   Color color1 = merge(color10, color11, remx, numerator);
146                   int remy = y * denominator % numerator;
147                   Color color = merge(color0, color1, remy, numerator);
148                   scaled.get_pixel(x, y) = color;
149                }
150             }
151             return scaled;
152          }
153       }
154
155       Surface Surface::h_flip() const
156       {
157          assert(pixels);
158          Surface flipped(get_size());
159          for(unsigned int y = 0;y < get_size().y;y++)
160          {
161             for(unsigned int x = 0;x < get_size().x;x++)
162             {
163                flipped.get_pixel(x, y) = get_pixel(get_size().x - x - 1, y);
164             }
165          }
166          return flipped;
167       }
168
169       Surface Surface::v_flip() const
170       {
171          assert(pixels);
172          Surface flipped(get_size());
173          for(unsigned int y = 0;y < get_size().y;y++)
174          {
175             for(unsigned int x = 0;x < get_size().x;x++)
176             {
177                flipped.get_pixel(x, y) = get_pixel(x, get_size().y - y - 1);
178             }
179          }
180          return flipped;
181       }
182
183       Surface Surface::modulate(const Color &color) const
184       {
185          assert(pixels);
186          if(color == Color::WHITE)
187          {
188             return *this;
189          }
190          else
191          {
192             Surface modulated(get_size());
193             for(unsigned int y = 0;y < get_size().y;y++)
194             {
195                for(unsigned int x = 0;x < get_size().x;x++)
196                {
197                   Color pixel = get_pixel(x, y);
198                   pixel.red = pixel.red * color.red / 0xff;
199                   pixel.green = pixel.green * color.green / 0xff;
200                   pixel.blue = pixel.blue * color.blue / 0xff;
201                   pixel.alpha = pixel.alpha * color.alpha / 0xff;
202                   modulated.get_pixel(x, y) = pixel;
203                }
204             }
205             return modulated;
206          }
207       }
208
209       Surface Surface::modulate(unsigned char alpha) const
210       {
211          assert(pixels);
212          if(alpha == 0xff)
213          {
214             return *this;
215          }
216          else
217          {
218             Surface modulated(get_size());
219             for(unsigned int y = 0;y < get_size().y;y++)
220             {
221                for(unsigned int x = 0;x < get_size().x;x++)
222                {
223                   Color pixel = get_pixel(x, y);
224                   pixel.alpha = pixel.alpha * alpha / 0xff;
225                   modulated.get_pixel(x, y) = pixel;
226                }
227             }
228             return modulated;
229          }
230       }
231
232       void Surface::cow()
233       {
234          if(pixels && pixels->refcount > 1)
235          {
236             PixelBuffer *original = pixels;
237             pixels = new PixelBuffer(pixels->size);
238             memcpy(pixels->buffer, original->buffer, pixels->size.x * pixels->size.y * sizeof(Color));
239          }
240       }
241    }
242 }