]> rtime.felk.cvut.cz Git - l4.git/blob - l4/pkg/mag-gfx/include/mem_canvas
b26ae66de5a3dc714ded0dcb24ac21c688f1dfa5
[l4.git] / l4 / pkg / mag-gfx / include / mem_canvas
1 // vi:ft=cpp
2 /*
3  * (c) 2010 Alexander Warg <warg@os.inf.tu-dresden.de>
4  *     economic rights: Technische Universität Dresden (Germany)
5  *
6  * This file is part of TUD:OS and distributed under the terms of the
7  * GNU General Public License 2.
8  * Please see the COPYING-GPL-2 file for details.
9  */
10 #pragma once
11
12 #include <l4/mag-gfx/canvas>
13 #include <l4/mag-gfx/mem_texture>
14 #include <l4/mag-gfx/font>
15 #include <l4/mag-gfx/blit>
16
17 namespace Mag_gfx {
18 namespace Mem {
19
20 template< typename PT >
21 class Canvas : public Mag_gfx::Canvas
22 {
23 public:
24   typedef PT Pixel_traits;
25   typedef typename PT::Pixel Pixel;
26   typedef typename PT::Color Color;
27
28 private:
29   char *_pixels;
30   Pixel_info const *_type;
31   int _bpl;
32
33 public:
34   Canvas(void *pixels, Area const &size, unsigned bpl)
35   : Mag_gfx::Canvas(size), _pixels((char *)pixels), _type(PT::type()), _bpl(bpl)
36   {}
37
38   Pixel_info const *type() const { return _type; }
39
40   void *buffer() const { return _pixels; }
41   void buffer(void *buf) { _pixels = (char *)buf; }
42   int bytes_per_line() const { return _bpl; }
43
44 private:
45   template< typename CT >
46   void _draw_box(char *dst_line, int _w, int h, CT color, int a)
47   {
48     Color const c = color_conv<Color>(color);
49     for (; h--; dst_line += _bpl)
50       {
51         int w;
52         Pixel *dst = reinterpret_cast<Pixel*>(dst_line);
53         for (w = _w; w--; dst++)
54           if (!CT::A::Size)
55             *dst = c;
56           else
57             *dst = Color::Traits::mix(*dst, c, a);
58       }
59   }
60
61   template< typename CT >
62   void __draw_string(Point const &p, Font const *font,
63                      typename CT::Color color,
64                      char const *_str, unsigned len)
65   {
66     enum { Alphas = CT::A::Size };
67     const unsigned char *str = (const unsigned char *)_str;
68     int x = p.x(), y = p.y();
69
70     if (!str || !font)
71       return;
72
73     unsigned char const *src = font->img;
74     int d, h = font->str_h(_str);
75
76     /* check top clipping */
77     if ((d = _clip.y1() - y) > 0)
78       {
79         src += d * font->w;
80         y += d;
81         h -= d;
82       }
83
84     /* check bottom clipping */
85     if ((d = y + h - 1 - _clip.y2()) > 0)
86       h -= d;
87
88     if (h < 1)
89       return;
90
91     /* skip hidden glyphs */
92     for ( ; *str && len && (x + font->wtab[*str] < _clip.x1()); --len)
93       x += font->wtab[*str++];
94
95     int x_start = x;
96
97     char *dst = _pixels + y * _bpl;
98     Color pix = color_conv<Color>(color);
99     int alpha = 255;
100     if (Alphas)
101       alpha = color.a() << (8 - Alphas);
102
103     /* draw glyphs */
104     for ( ; *str && len && (x <= _clip.x2()); ++str, --len)
105       {
106         int w = font->wtab[*str];
107         int start = std::max(0, _clip.x1() - x);
108         int end = std::min(w - 1, _clip.x2() - x);
109         char *d = dst + x * sizeof(Pixel);
110         unsigned char const *s = src + font->otab[*str];
111
112         for (int j = 0; j < h; ++j, s += font->w, d += _bpl)
113           for (int i = start; i <= end; ++i)
114             if (s[i])
115               {
116                 Pixel *p = reinterpret_cast<Pixel *>(d) + i;
117                 *p = Pixel_traits::mix(*p, pix, (alpha * s[i]) >> 8);
118               }
119
120         x += w;
121       }
122
123     flush_pixels(Rect(Point(x_start, y), Area(x - x_start + 1, h)));
124   }
125
126   bool _draw_alpha_texture(Texture<Pixel_traits> const *texture,
127       Pixel const *src, char *dst, int offset,
128       int h, int w, int src_w)
129   {
130     typedef typename Pixel_traits::Pixel Pixel;
131     bool xa = !Pixel_traits::A::Size && texture->extra_alpha();
132     if (!xa && !Pixel_traits::A::Size)
133       return false;
134
135     unsigned char const *ab;
136     if (xa)
137       ab = texture->alpha_buffer() + offset;
138
139     for (int j = h; j--; src += src_w, dst += _bpl)
140       {
141         Pixel *dp = reinterpret_cast<Pixel*>(dst);
142         Pixel const *s = src;
143         unsigned char const *sab = ab;
144
145         for (int i = w; i--; ++s, ++dp)
146           {
147             int alpha;
148             if (!xa)
149               alpha = Color(*s).a() << (8 - Pixel_traits::A::Size);
150             else
151               alpha = *sab++;
152
153             if (alpha < 255)
154               *dp = Pixel_traits::mix(*dp, *s, alpha);
155             else if (alpha > 0)
156               *dp = *s;
157           }
158         if (xa)
159           ab += src_w;
160       }
161     return true;
162   }
163
164 public:
165   void draw_box(Rect const &rect, Rgba32::Color color)
166   {
167     Rect const clipped = _clip & rect;
168     if (!clipped.valid() || color.a() == 0)
169       return;
170
171     char *dst_line = _pixels + _bpl*clipped.y1() + sizeof(Pixel)*clipped.x1();
172
173     if (color.a() >= 255)
174       _draw_box(dst_line, clipped.w(), clipped.h(), Rgb32::Color(color.v()), 0);
175     else
176       _draw_box(dst_line, clipped.w(), clipped.h(), color, color.a());
177
178     flush_pixels(clipped);
179   }
180
181   void draw_string(Point const &p, Font const *font, Rgba32::Color color,
182                    char const *_str, unsigned len)
183   {
184     if (color.a() != Rgba32::Color::Amax)
185       __draw_string<Rgba32>(p, font, color, _str, len);
186     else
187       __draw_string<Rgb32>(p, font, Rgb32::Color(color.v()), _str, len);
188   }
189
190   void draw_texture(Mag_gfx::Texture const *texture, Rgb32::Color mix_color,
191                     Point const &pos, Mix_mode mode)
192   {
193     Rect const clipped = _clip & Rect(pos, texture->size());
194
195     if (!clipped.valid())
196       return;
197
198     int src_w = texture->size().w();
199     Texture<Pixel_traits> const *txt;
200     txt = static_cast<Texture<Pixel_traits> const *>(texture);
201     Pixel const *src = txt->pixels()
202       + (clipped.y1() - pos.y()) * src_w
203       +  clipped.x1() - pos.x();
204
205     char *dst = _pixels + clipped.y1() * _bpl + clipped.x1() * sizeof(Pixel);
206     char *d;
207
208     int i, j;
209     Pixel const *s;
210     Color mix_pixel = color_conv<Color>(mix_color);
211
212     switch (mode)
213       {
214       case Alpha:
215         if (_draw_alpha_texture(txt, src, dst,
216               (clipped.y1() - pos.y()) * src_w +  clipped.x1() - pos.x(),
217               clipped.h(), clipped.w(), src_w))
218           break;
219         // Fall through to solid!
220       case Solid:
221 //      for (j = clipped.h(); j--; src += src_w, dst += _bpl)
222 //        for (i = clipped.w(), s = src, d = dst; i--; ++s, d += sizeof(Pixel))
223 //          *reinterpret_cast<Pixel*>(d) = *s;
224         Blit::blit(src, src_w * sizeof(Pixel),
225              dst, _bpl, clipped.w() * sizeof(Pixel), clipped.h());
226         break;
227
228       case Mixed:
229         mix_pixel = color_50(mix_pixel);
230         for (j = clipped.h(); j--; src += src_w, dst += _bpl)
231           for (i = clipped.w(), s = src, d = dst; i--; ++s, d += sizeof(Pixel))
232             *reinterpret_cast<Pixel*>(d) = color_50(Color(*s)) + mix_pixel;
233         break;
234
235       case Masked:
236         for (j = clipped.h(); j--; src += src_w, dst += _bpl)
237           for (i = clipped.w(), s = src, d = dst; i--; ++s, d += sizeof(Pixel))
238             if (s->v())
239               *reinterpret_cast<Pixel*>(d) = *s;
240         break;
241     }
242
243     flush_pixels(clipped);
244   }
245
246 };
247
248 }}