genode/repos/demo/include/scout_gfx/sky_texture_painter.h

269 lines
6.9 KiB
C++

/*
* \brief Functor for drawing a sky texture into a surface
* \author Norman Feske
* \date 2005-10-24
*/
/*
* Copyright (C) 2006-2017 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU Affero General Public License version 3.
*/
#ifndef _INCLUDE__SCOUT_GFX__SKY_TEXTURE_PAINTER_H_
#define _INCLUDE__SCOUT_GFX__SKY_TEXTURE_PAINTER_H_
#include <os/surface.h>
#include <util/color.h>
struct Sky_texture_painter
{
typedef Genode::Surface_base::Area Area;
typedef Genode::Surface_base::Rect Rect;
typedef Genode::Color Color;
template <typename PT>
static void _compose(PT *dst, int dst_w, int dst_h, int x_start, int x_end,
short const src1[], int src1_y,
short const src2[], int src2_y,
short const src3[], int src3_y, int src_w, int src_h,
PT const coltab[])
{
for (int k = 0; k <= x_end; k += src_w) {
int x_offset = Genode::max(0, x_start - k);
int x_max = Genode::min(x_end - k, src_w - 1);
for (int j = 0; j < dst_h; j++) {
short const *s1 = src1 + x_offset + ((src1_y + j)%src_h)*src_w;
short const *s2 = src2 + x_offset + ((src2_y + j)%src_h)*src_w;
short const *s3 = src3 + x_offset + ((src3_y + j)%src_h)*src_w;
PT *d = dst + x_offset + j*dst_w + k;
for (int i = x_offset; i <= x_max; i++)
*d++ = coltab[*s1++ + *s2++ + *s3++];
}
}
}
class Sky_texture_base
{
protected:
virtual ~Sky_texture_base() { }
static void _brew_texture(short tmp[], short tmp2[], short dst[], int w, int h,
int lf_start, int lf_end, int lf_incr, int lf_mul,
int hf_val, int hf_mul);
/**
* Multiply buffer values with 24:8 fixpoint value
*/
static void _multiply_buf(short dst[], int len, int factor)
{
for (int i = 0; i < len; i++)
dst[i] = (dst[i]*factor)>>8;
}
static inline int _mix_channel(int value1, int value2, int alpha)
{
return (value1*(255 - alpha) + value2*alpha)>>8;
}
};
template <typename PT>
class Sky_texture : public Sky_texture_base
{
private:
Area _size;
public:
Sky_texture(Area size) : _size(size) { }
virtual ~Sky_texture() { }
virtual PT const *fallback() const = 0;
virtual short const *buf(unsigned i) const = 0;
virtual PT const *coltab() const = 0;
Area size() const { return _size; }
};
/*
* The texture is composed of four generated 4-bit maps based on bicubic
* interpolation of some noise at different frequencies. At runtime, we
* overlay (add their values) the generated map and use the result as index
* of a color table.
*/
template <typename PT, unsigned TW, unsigned TH>
class Static_sky_texture : public Sky_texture<PT>
{
private:
short _bufs[3][TH][TW];
short _buf[TH][TW];
short _tmp[TH][TW];
PT _coltab[16*16*16];
PT _fallback[TH][TW]; /* fallback texture */
using Sky_texture<PT>::_mix_channel;
using Sky_texture<PT>::_brew_texture;
using Sky_texture<PT>::_multiply_buf;
public:
/**
* Create 3D color table
*/
static void _create_coltab(PT *dst, Color c0, Color c1, Color c2, Color bg)
{
for (int i = 0; i < 16; i++)
for (int j = 0; j < 16; j++)
for (int k = 0; k < 16; k++) {
int r = bg.r;
int g = bg.g;
int b = bg.b;
r = _mix_channel(r, c2.r, k*16);
g = _mix_channel(g, c2.g, k*16);
b = _mix_channel(b, c2.b, k*16);
r = _mix_channel(r, c1.r, j*16);
g = _mix_channel(g, c1.g, j*16);
b = _mix_channel(b, c1.b, j*16);
r = _mix_channel(r, c0.r, i*8);
g = _mix_channel(g, c0.g, i*8);
b = _mix_channel(b, c0.b, i*8);
int v = (((i ^ j ^ k)<<1) & 0xff) + 128 + 64;
r = (r + v)>>1;
g = (g + v)>>1;
b = (b + v)>>1;
v = 180;
r = (v*r + (255 - v)*255)>>8;
g = (v*g + (255 - v)*255)>>8;
b = (v*b + (255 - v)*255)>>8;
dst[(k<<8) + (j<<4) + i].rgba(r, g, b);
}
}
/**
* Constructor
*/
Static_sky_texture()
:
Sky_texture<PT>(Area(TW, TH))
{
/* create nice-looking textures */
_brew_texture(_tmp[0], _buf[0], _bufs[0][0], TW, TH, 3, 7, 1, 30, 30, 10);
_brew_texture(_tmp[0], _buf[0], _bufs[1][0], TW, TH, 3, 16, 3, 50, 40, 30);
_brew_texture(_tmp[0], _buf[0], _bufs[2][0], TW, TH, 5, 40, 11, 70, 0, 0);
/* shift texture 1 to bits 4 to 7 */
_multiply_buf(_bufs[1][0], TW*TH, 16*256);
/* shift texture 2 to bits 8 to 11 */
_multiply_buf(_bufs[2][0], TW*TH, 16*16*256);
/* create color table */
_create_coltab(_coltab, Color(255, 255, 255),
Color( 0, 0, 0),
Color(255, 255, 255),
Color( 80, 88, 112));
/* create fallback texture */
_compose(_fallback[0], TW, TH, 0, TW - 1,
_bufs[0][0], 0, _bufs[1][0], 0, _bufs[2][0], 0,
TW, TH, _coltab);
}
PT const *fallback() const override { return _fallback[0]; }
short const *buf(unsigned i) const override
{
if (i >= 3)
return 0;
return _bufs[i][0];
}
PT const *coltab() const override { return _coltab; }
};
template <typename PT>
static void _copy(PT *dst, int dst_w, int dst_h, int x_start, int x_end,
PT const *src, int src_y, int src_w, int src_h)
{
for (int k = 0; k <= x_end; k += src_w) {
int x_offset = Genode::max(0, x_start - k);
int x_max = Genode::min(x_end - k, src_w - 1);
for (int j = 0; j < dst_h; j++) {
PT const *s = src + x_offset + ((src_y + j)%src_h)*src_w;
PT *d = dst + x_offset + j*dst_w + k;
if (x_max - x_offset >= 0)
Genode::memcpy(d, s, (x_max - x_offset + 1)*sizeof(PT));
}
}
}
template <typename PT>
static inline void paint(Genode::Surface<PT> &surface, int py,
Sky_texture_base const &texture_base,
bool detail)
{
PT *addr = surface.addr();
if (!addr) return;
Sky_texture<PT> const &texture = static_cast<Sky_texture<PT> const &>(texture_base);
int cx1 = surface.clip().x1();
int cy1 = surface.clip().y1();
int cx2 = surface.clip().x2();
int cy2 = surface.clip().y2();
int v = -py;
int y0 = cy1 + v;
int y1 = cy1 + (( (5*v)/16)%texture.size().h());
int y2 = cy1 + (((11*v)/16)%texture.size().h());
addr += cy1*surface.size().w();
if (detail == false) {
_copy(addr, surface.size().w(), cy2 - cy1 + 1, cx1, cx2,
texture.fallback(), cy1 - py, texture.size().w(), texture.size().h());
return;
}
_compose(addr, surface.size().w(), cy2 - cy1 + 1, cx1, cx2,
texture.buf(0), y0, texture.buf(1), y1, texture.buf(2), y2,
texture.size().w(), texture.size().h(), texture.coltab());
surface.flush_pixels(surface.clip());
}
};
#endif /* _INCLUDE__SCOUT_GFX__SKY_TEXTURE_PAINTER_H_ */