private:
template< typename CT >
- void _draw_box(char *dst_line, int _w, int h, CT color, int a)
- {
- Color const c = color_conv<Color>(color);
- for (; h--; dst_line += _bpl)
- {
- int w;
- Pixel *dst = reinterpret_cast<Pixel*>(dst_line);
- for (w = _w; w--; dst++)
- if (!CT::A::Size)
- *dst = c;
- else
- *dst = Color::Traits::mix(*dst, c, a);
- }
- }
+ void _draw_box(char *dst_line, int _w, int h, CT color, int a);
template< typename CT >
void __draw_string(Point const &p, Font const *font,
typename CT::Color color,
- char const *_str, unsigned len)
- {
- enum { Alphas = CT::A::Size };
- const unsigned char *str = (const unsigned char *)_str;
- int x = p.x(), y = p.y();
-
- if (!str || !font)
- return;
-
- unsigned char const *src = font->img;
- int d, h = font->str_h(_str);
-
- /* check top clipping */
- if ((d = _clip.y1() - y) > 0)
- {
- src += d * font->w;
- y += d;
- h -= d;
- }
-
- /* check bottom clipping */
- if ((d = y + h - 1 - _clip.y2()) > 0)
- h -= d;
-
- if (h < 1)
- return;
-
- /* skip hidden glyphs */
- for ( ; *str && len && (x + font->wtab[*str] < _clip.x1()); --len)
- x += font->wtab[*str++];
-
- int x_start = x;
-
- char *dst = _pixels + y * _bpl;
- Color pix = color_conv<Color>(color);
- int alpha = 255;
- if (Alphas)
- alpha = color.a() << (8 - Alphas);
-
- /* draw glyphs */
- for ( ; *str && len && (x <= _clip.x2()); ++str, --len)
- {
- int w = font->wtab[*str];
- int start = std::max(0, _clip.x1() - x);
- int end = std::min(w - 1, _clip.x2() - x);
- char *d = dst + x * sizeof(Pixel);
- unsigned char const *s = src + font->otab[*str];
-
- for (int j = 0; j < h; ++j, s += font->w, d += _bpl)
- for (int i = start; i <= end; ++i)
- if (s[i])
- {
- Pixel *p = reinterpret_cast<Pixel *>(d) + i;
- *p = Pixel_traits::mix(*p, pix, (alpha * s[i]) >> 8);
- }
-
- x += w;
- }
-
- flush_pixels(Rect(Point(x_start, y), Area(x - x_start + 1, h)));
- }
+ char const *_str, unsigned len);
bool _draw_alpha_texture(Texture<Pixel_traits> const *texture,
Pixel const *src, char *dst, int offset,
- int h, int w, int src_w)
- {
- typedef typename Pixel_traits::Pixel Pixel;
- bool xa = !Pixel_traits::A::Size && texture->extra_alpha();
- if (!xa && !Pixel_traits::A::Size)
- return false;
-
- unsigned char const *ab;
- if (xa)
- ab = texture->alpha_buffer() + offset;
-
- for (int j = h; j--; src += src_w, dst += _bpl)
- {
- Pixel *dp = reinterpret_cast<Pixel*>(dst);
- Pixel const *s = src;
- unsigned char const *sab = ab;
-
- for (int i = w; i--; ++s, ++dp)
- {
- int alpha;
- if (!xa)
- alpha = Color(*s).a() << (8 - Pixel_traits::A::Size);
- else
- alpha = *sab++;
-
- if (alpha < 255)
- *dp = Pixel_traits::mix(*dp, *s, alpha);
- else if (alpha > 0)
- *dp = *s;
- }
- if (xa)
- ab += src_w;
- }
- return true;
- }
+ int h, int w, int src_w);
public:
void draw_box(Rect const &rect, Rgba32::Color color)
}
void draw_texture(Mag_gfx::Texture const *texture, Rgb32::Color mix_color,
- Point const &pos, Mix_mode mode)
- {
- Rect const clipped = _clip & Rect(pos, texture->size());
+ Point const &pos, Mix_mode mode);
- if (!clipped.valid())
- return;
+ void draw_texture_scaled(Mag_gfx::Texture const *texture, Area const &size,
+ Rgb32::Color mix_color, Point const &pos,
+ Mix_mode mode);
- int src_w = texture->size().w();
- Texture<Pixel_traits> const *txt;
- txt = static_cast<Texture<Pixel_traits> const *>(texture);
- Pixel const *src = txt->pixels()
- + (clipped.y1() - pos.y()) * src_w
- + clipped.x1() - pos.x();
-
- char *dst = _pixels + clipped.y1() * _bpl + clipped.x1() * sizeof(Pixel);
- char *d;
-
- int i, j;
- Pixel const *s;
- Color mix_pixel = color_conv<Color>(mix_color);
-
- switch (mode)
- {
- case Alpha:
- if (_draw_alpha_texture(txt, src, dst,
- (clipped.y1() - pos.y()) * src_w + clipped.x1() - pos.x(),
- clipped.h(), clipped.w(), src_w))
- break;
- // Fall through to solid!
- case Solid:
-// for (j = clipped.h(); j--; src += src_w, dst += _bpl)
-// for (i = clipped.w(), s = src, d = dst; i--; ++s, d += sizeof(Pixel))
-// *reinterpret_cast<Pixel*>(d) = *s;
- Blit::blit(src, src_w * sizeof(Pixel),
- dst, _bpl, clipped.w() * sizeof(Pixel), clipped.h());
- break;
+};
- case Mixed:
- mix_pixel = color_50(mix_pixel);
- for (j = clipped.h(); j--; src += src_w, dst += _bpl)
- for (i = clipped.w(), s = src, d = dst; i--; ++s, d += sizeof(Pixel))
- *reinterpret_cast<Pixel*>(d) = color_50(Color(*s)) + mix_pixel;
- break;
- case Masked:
- for (j = clipped.h(); j--; src += src_w, dst += _bpl)
- for (i = clipped.w(), s = src, d = dst; i--; ++s, d += sizeof(Pixel))
- if (s->v())
- *reinterpret_cast<Pixel*>(d) = *s;
+template< typename PT>
+template< typename CT >
+void
+Canvas<PT>::_draw_box(char *dst_line, int _w, int h, CT color, int a)
+{
+ Color const c = color_conv<Color>(color);
+ for (; h--; dst_line += _bpl)
+ {
+ int w;
+ Pixel *dst = reinterpret_cast<Pixel*>(dst_line);
+ for (w = _w; w--; dst++)
+ if (!CT::A::Size)
+ *dst = c;
+ else
+ *dst = Color::Traits::mix(*dst, c, a);
+ }
+}
+
+template< typename PT>
+template< typename CT >
+void
+Canvas<PT>::__draw_string(Point const &p, Font const *font,
+ typename CT::Color color,
+ char const *_str, unsigned len)
+{
+ enum { Alphas = CT::A::Size };
+ const unsigned char *str = (const unsigned char *)_str;
+ int x = p.x(), y = p.y();
+
+ if (!str || !font)
+ return;
+
+ unsigned char const *src = font->img;
+ int d, h = font->str_h(_str);
+
+ /* check top clipping */
+ if ((d = _clip.y1() - y) > 0)
+ {
+ src += d * font->w;
+ y += d;
+ h -= d;
+ }
+
+ /* check bottom clipping */
+ if ((d = y + h - 1 - _clip.y2()) > 0)
+ h -= d;
+
+ if (h < 1)
+ return;
+
+ /* skip hidden glyphs */
+ for ( ; *str && len && (x + font->wtab[*str] < _clip.x1()); --len)
+ x += font->wtab[*str++];
+
+ int x_start = x;
+
+ char *dst = _pixels + y * _bpl;
+ Color pix = color_conv<Color>(color);
+ int alpha = 255;
+ if (Alphas)
+ alpha = color.a() << (8 - Alphas);
+
+ /* draw glyphs */
+ for ( ; *str && len && (x <= _clip.x2()); ++str, --len)
+ {
+ int w = font->wtab[*str];
+ int start = std::max(0, _clip.x1() - x);
+ int end = std::min(w - 1, _clip.x2() - x);
+ char *d = dst + x * sizeof(Pixel);
+ unsigned char const *s = src + font->otab[*str];
+
+ for (int j = 0; j < h; ++j, s += font->w, d += _bpl)
+ for (int i = start; i <= end; ++i)
+ if (s[i])
+ {
+ Pixel *p = reinterpret_cast<Pixel *>(d) + i;
+ *p = Pixel_traits::mix(*p, pix, (alpha * s[i]) >> 8);
+ }
+
+ x += w;
+ }
+
+ flush_pixels(Rect(Point(x_start, y), Area(x - x_start + 1, h)));
+}
+
+template<typename PT>
+bool
+Canvas<PT>::_draw_alpha_texture(Texture<Pixel_traits> const *texture,
+ Pixel const *src, char *dst, int offset,
+ int h, int w, int src_w)
+{
+ typedef typename Pixel_traits::Pixel Pixel;
+ bool xa = !Pixel_traits::A::Size && texture->extra_alpha();
+ if (!xa && !Pixel_traits::A::Size)
+ return false;
+
+ unsigned char const *ab;
+ if (xa)
+ ab = texture->alpha_buffer() + offset;
+
+ for (int j = h; j--; src += src_w, dst += _bpl)
+ {
+ Pixel *dp = reinterpret_cast<Pixel*>(dst);
+ Pixel const *s = src;
+ unsigned char const *sab = ab;
+
+ for (int i = w; i--; ++s, ++dp)
+ {
+ int alpha;
+ if (!xa)
+ alpha = Color(*s).a() << (8 - Pixel_traits::A::Size);
+ else
+ alpha = *sab++;
+
+ if (alpha < 255)
+ *dp = Pixel_traits::mix(*dp, *s, alpha);
+ else if (alpha > 0)
+ *dp = *s;
+ }
+ if (xa)
+ ab += src_w;
+ }
+ return true;
+}
+
+template<typename PT>
+void
+Canvas<PT>::draw_texture(Mag_gfx::Texture const *texture,
+ Rgb32::Color mix_color, Point const &pos,
+ Mix_mode mode)
+{
+ Rect const clipped = _clip & Rect(pos, texture->size());
+
+ if (!clipped.valid())
+ return;
+
+ int src_w = texture->size().w();
+ Texture<Pixel_traits> const *txt;
+ txt = static_cast<Texture<Pixel_traits> const *>(texture);
+ Pixel const *src = txt->pixels()
+ + (clipped.y1() - pos.y()) * src_w
+ + clipped.x1() - pos.x();
+
+ char *dst = _pixels + clipped.y1() * _bpl + clipped.x1() * sizeof(Pixel);
+ char *d;
+
+ int i, j;
+ Pixel const *s;
+ Color mix_pixel = color_conv<Color>(mix_color);
+
+ switch (mode)
+ {
+ case Alpha:
+ if (_draw_alpha_texture(txt, src, dst,
+ (clipped.y1() - pos.y()) * src_w + clipped.x1() - pos.x(),
+ clipped.h(), clipped.w(), src_w))
break;
+ // Fall through to solid!
+ case Solid:
+ // for (j = clipped.h(); j--; src += src_w, dst += _bpl)
+ // for (i = clipped.w(), s = src, d = dst; i--; ++s, d += sizeof(Pixel))
+ // *reinterpret_cast<Pixel*>(d) = *s;
+ Blit::blit(src, src_w * sizeof(Pixel),
+ dst, _bpl, clipped.w() * sizeof(Pixel), clipped.h());
+ break;
+
+ case Mixed:
+ mix_pixel = color_50(mix_pixel);
+ for (j = clipped.h(); j--; src += src_w, dst += _bpl)
+ for (i = clipped.w(), s = src, d = dst; i--; ++s, d += sizeof(Pixel))
+ *reinterpret_cast<Pixel*>(d) = color_50(Color(*s)) + mix_pixel;
+ break;
+
+ case Masked:
+ for (j = clipped.h(); j--; src += src_w, dst += _bpl)
+ for (i = clipped.w(), s = src, d = dst; i--; ++s, d += sizeof(Pixel))
+ if (s->v())
+ *reinterpret_cast<Pixel*>(d) = *s;
+ break;
}
- flush_pixels(clipped);
- }
+ flush_pixels(clipped);
+}
+
+template< typename Pixel, typename Op >
+inline
+void
+draw_loop(Area const &area, unsigned const *cb, unsigned const *rb,
+ unsigned bpl,
+ char const *src, char *dst, Op const &op)
+{
+ char const *s;
+ char *d;
+ int i, j;
+ for (j = area.h(); j--; dst += bpl)
+ for (i = area.w(), s = src + rb[j], d = dst; i--; d += sizeof(Pixel))
+ op(reinterpret_cast<Pixel*>(d), reinterpret_cast<Pixel const *>(s + cb[i]));
+}
+
+
+namespace {
+static inline void
+calc_xscale_buffer(unsigned dx, unsigned dy, unsigned s, unsigned w, unsigned sbpp, unsigned *sb)
+{
+ int f = dx / 2;
+ unsigned y = 0;
+ unsigned x = 0;
+
+ for (x = 0; x < s; ++x)
+ {
+ f = f - dy;
+ if (f < 0)
+ {
+ y += sbpp;
+ f = f + dx;
+ }
+ }
+
+ for (x = w; x--;)
+ {
+ f = f - dy;
+ sb[x] = y;
+ if (f < 0)
+ {
+ y += sbpp;
+ f = f + dx;
+ }
+ }
+}
+
+static inline void
+calc_yscale_buffer(unsigned dx, unsigned dy, unsigned s, unsigned w, unsigned sbpp, unsigned *sb)
+{
+ int f = dx / 2;
+ unsigned y = 0;
+ unsigned x = 0;
+ unsigned xv = 0;
+
+ for (x = 0; y < s && x < dx; ++x)
+ {
+ f = f - dy;
+ if (f < 0)
+ {
+ f = f + dx;
+ if (y >= s)
+ break;
+ ++y;
+ }
+ xv += sbpp;
+ }
+
+ y = w - 1;
+ sb[y] = xv;
+
+ if (!y)
+ return;
+
+ for (;x < dx; ++x)
+ {
+ f = f - dy;
+ if (f < 0)
+ {
+ f = f + dx;
+ --y;
+ sb[y] = xv;
+ if (y == 0)
+ return;
+ }
+ xv += sbpp;
+ }
+}
+
+template< typename Pixel >
+struct Solid_copy
+{ void operator () (Pixel *d, Pixel const *s) const { *d = *s; } };
+
+template< typename Pixel, typename Color >
+struct Mix_50_copy
+{
+ Color mix_pixel;
+ Mix_50_copy(Rgb32::Color mix_color)
+ : mix_pixel(color_conv<Color>(mix_color))
+ {}
+ void operator () (Pixel *d, Pixel const *s) const
+ { *d = color_50(Color(*s)) + mix_pixel; }
};
+template< typename Pixel >
+struct Masked_copy
+{
+ void operator () (Pixel *d, Pixel const *s) const
+ {
+ if (s->v()) *d = *s;
+ }
+};
+}
+
+template<typename PT>
+void
+Canvas<PT>::draw_texture_scaled(Mag_gfx::Texture const *texture,
+ Area const &size,
+ Rgb32::Color mix_color, Point const &pos,
+ Mix_mode mode)
+{
+ Rect const clipped = _clip & Rect(pos, size); //texture->size());
+
+ if (!clipped.valid())
+ return;
+
+ Point tl_offs = clipped.p1() - pos;
+ unsigned *col_buf = (unsigned*)alloca(sizeof(unsigned) * clipped.w());
+ unsigned *row_buf = (unsigned*)alloca(sizeof(unsigned) * clipped.h());
+
+ Area ts = texture->size();
+
+ if (size.w() > ts.w())
+ calc_xscale_buffer(size.w(), ts.w(), tl_offs.x(), clipped.w(), sizeof(Pixel), col_buf);
+ else
+ calc_yscale_buffer(ts.w(), size.w(), tl_offs.x(), clipped.w(), sizeof(Pixel), col_buf);
+
+ if (size.h() > ts.h())
+ calc_xscale_buffer(size.h(), ts.h(), tl_offs.y(), clipped.h(), ts.w() * sizeof(Pixel), row_buf);
+ else
+ calc_yscale_buffer(ts.h(), size.h(), tl_offs.y(), clipped.h(), ts.w() * sizeof(Pixel), row_buf);
+
+ char const *src = (char const *)texture->pixels();
+ char *dst = _pixels + clipped.y1() * _bpl + clipped.x1() * sizeof(Pixel);
+
+ Mix_50_copy<Pixel, Color> mix_copy(mix_color);
+
+ switch (mode)
+ {
+ case Alpha:
+#if 0
+ if (_draw_alpha_texture(txt, src, dst,
+ (clipped.y1() - pos.y()) * src_w + clipped.x1() - pos.x(),
+ clipped.h(), clipped.w(), src_w))
+ break;
+#endif
+ // Fall through to solid!
+ case Solid:
+ draw_loop<Pixel>(clipped.area(), col_buf, row_buf, _bpl, src, dst, Solid_copy<Pixel>());
+ break;
+
+ case Mixed:
+ draw_loop<Pixel>(clipped.area(), col_buf, row_buf, _bpl, src, dst, mix_copy);
+ break;
+
+ case Masked:
+ draw_loop<Pixel>(clipped.area(), col_buf, row_buf, _bpl, src, dst, Masked_copy<Pixel>());
+ break;
+ }
+
+ flush_pixels(clipped);
+}
+
}}