genode/os/include/nitpicker_gfx/chunky_canvas.h

203 lines
4.8 KiB
C
Raw Normal View History

2011-12-22 15:19:25 +00:00
/*
* \brief Canvas storing each pixel in one storage unit in a linear buffer
* \author Norman Feske
* \date 2006-08-04
*/
/*
2013-01-10 20:44:47 +00:00
* Copyright (C) 2006-2013 Genode Labs GmbH
2011-12-22 15:19:25 +00:00
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
*/
#ifndef _INCLUDE__NITPICKER_GFX__CHUNKY_CANVAS_H_
#define _INCLUDE__NITPICKER_GFX__CHUNKY_CANVAS_H_
#include <blit/blit.h>
#include "canvas.h"
template <typename PT>
class Chunky_texture : public Texture
{
private:
2013-09-07 00:02:26 +00:00
PT const *_pixels;
unsigned char const *_alpha;
2011-12-22 15:19:25 +00:00
public:
2013-09-07 00:02:26 +00:00
Chunky_texture(PT const *pixels, unsigned char const *alpha, Area size)
: Texture(size), _pixels(pixels), _alpha(alpha) { }
2011-12-22 15:19:25 +00:00
2013-09-07 00:02:26 +00:00
PT const *pixels() const { return _pixels; }
2011-12-22 15:19:25 +00:00
2013-09-07 00:02:26 +00:00
unsigned char const *alpha() const { return _alpha; }
2011-12-22 15:19:25 +00:00
};
/*
* \param PT pixel type
*/
template <typename PT>
class Chunky_canvas : public Canvas
{
protected:
PT *_addr; /* base address of pixel buffer */
public:
/**
* Constructor
*/
Chunky_canvas(PT *addr, Area size): Canvas(size), _addr(addr) { }
/****************************************
** Implementation of Canvas interface **
****************************************/
void draw_box(Rect rect, Color color)
{
Rect clipped = Rect::intersect(_clip, rect);
if (!clipped.valid()) return;
PT pix(color.r, color.g, color.b);
PT *dst, *dst_line = _addr + _size.w()*clipped.y1() + clipped.x1();
for (int w, h = clipped.h() ; h--; dst_line += _size.w())
for (dst = dst_line, w = clipped.w(); w--; dst++)
*dst = pix;
_flush_pixels(clipped);
}
2013-09-07 00:02:26 +00:00
void draw_string(Point p, Font const &font, Color color, char const *sstr)
2011-12-22 15:19:25 +00:00
{
2013-09-07 00:02:26 +00:00
unsigned char const *str = (unsigned char const *)sstr;
2011-12-22 15:19:25 +00:00
int x = p.x(), y = p.y();
2013-09-07 00:02:26 +00:00
unsigned char const *src = font.img;
int d, h = font.img_h;
2011-12-22 15:19:25 +00:00
/* check top clipping */
if ((d = _clip.y1() - y) > 0) {
2013-09-07 00:02:26 +00:00
src += d*font.img_w;
2011-12-22 15:19:25 +00:00
y += d;
h -= d;
}
/* check bottom clipping */
if ((d = y + h -1 - _clip.y2()) > 0)
h -= d;
if (h < 1) return;
/* skip hidden glyphs */
2013-09-07 00:02:26 +00:00
for ( ; *str && (x + font.wtab[*str] < _clip.x1()); )
x += font.wtab[*str++];
2011-12-22 15:19:25 +00:00
int x_start = x;
PT *dst = _addr + y*_size.w();
PT pix(color.r, color.g, color.b);
/* draw glyphs */
for ( ; *str && (x <= _clip.x2()); str++) {
2013-09-07 00:02:26 +00:00
int w = font.wtab[*str];
2012-10-09 12:28:23 +00:00
int start = max(0, _clip.x1() - x);
int end = min(w - 1, _clip.x2() - x);
PT *d = dst + x;
2013-09-07 00:02:26 +00:00
unsigned char const *s = src + font.otab[*str];
2011-12-22 15:19:25 +00:00
2013-09-07 00:02:26 +00:00
for (int j = 0; j < h; j++, s += font.img_w, d += _size.w())
2011-12-22 15:19:25 +00:00
for (int i = start; i <= end; i++)
if (s[i]) d[i] = pix;
x += w;
}
_flush_pixels(Rect(Point(x_start, y), Area(x - x_start + 1, h)));
}
2013-09-07 00:02:26 +00:00
void draw_texture(Texture const &texture, Color mix_color, Point position,
2011-12-22 15:19:25 +00:00
Mode mode, bool allow_alpha)
{
2013-09-07 00:02:26 +00:00
Rect clipped = Rect::intersect(Rect(position, texture), _clip);
2011-12-22 15:19:25 +00:00
if (!clipped.valid()) return;
2013-09-07 00:02:26 +00:00
int const src_w = texture.w();
int const dst_w = _size.w();
2011-12-22 15:19:25 +00:00
2013-09-07 00:02:26 +00:00
Chunky_texture<PT> const &tex = static_cast<Chunky_texture<PT> const &>(texture);
2011-12-22 15:19:25 +00:00
/* calculate offset of first texture pixel to copy */
unsigned long tex_start_offset = (clipped.y1() - position.y())*src_w
+ clipped.x1() - position.x();
/* start address of source pixels */
2013-09-07 00:02:26 +00:00
PT const *src = tex.pixels() + tex_start_offset;
2011-12-22 15:19:25 +00:00
/* start address of source alpha values */
2013-09-07 00:02:26 +00:00
unsigned char const *alpha = tex.alpha() + tex_start_offset;
2011-12-22 15:19:25 +00:00
/* start address of destination pixels */
PT *dst = _addr + clipped.y1()*dst_w + clipped.x1();
PT mix_pixel(mix_color.r, mix_color.g, mix_color.b);
int i, j;
2013-09-07 00:02:26 +00:00
PT const *s;
PT *d;
unsigned char const *a;
2011-12-22 15:19:25 +00:00
switch (mode) {
case SOLID:
/*
* If the texture has no alpha channel, we can use
* a plain pixel blit.
*/
2013-09-07 00:02:26 +00:00
if (tex.alpha() == 0 || !allow_alpha) {
2011-12-22 15:19:25 +00:00
blit(src, src_w*sizeof(PT),
dst, dst_w*sizeof(PT),
clipped.w()*sizeof(PT), clipped.h());
break;
}
/*
* Copy texture with alpha blending
*/
for (j = clipped.h(); j--; src += src_w, alpha += src_w, dst += dst_w)
for (i = clipped.w(), s = src, a = alpha, d = dst; i--; s++, d++, a++)
if (*a)
*d = PT::mix(*d, *s, *a);
break;
case MIXED:
for (j = clipped.h(); j--; src += src_w, dst += dst_w)
for (i = clipped.w(), s = src, d = dst; i--; s++, d++)
*d = PT::avr(mix_pixel, *s);
break;
case MASKED:
for (j = clipped.h(); j--; src += src_w, dst += dst_w)
for (i = clipped.w(), s = src, d = dst; i--; s++, d++)
if (s->pixel) *d = *s;
break;
}
_flush_pixels(clipped);
}
};
#endif /* _INCLUDE__NITPICKER_GFX__CHUNKY_CANVAS_H_ */