mirror of
https://github.com/genodelabs/genode.git
synced 2024-12-30 10:38:55 +00:00
gems: new backdrop application
The new backdrop found at gems/src/app/backdrop replaces the old program that was hosted in the demo repository.
This commit is contained in:
parent
6a46dcd2af
commit
61b370ecba
@ -1,19 +0,0 @@
|
||||
This directory contains a simple backdrop program for Nitpicker.
|
||||
|
||||
|
||||
Usage
|
||||
-----
|
||||
|
||||
You have to specify the name of the PNG file to be used as background
|
||||
image via a declaration in your config file:
|
||||
|
||||
! <config>
|
||||
! <image>background.png</image>
|
||||
! </config>
|
||||
|
||||
|
||||
Limitations
|
||||
-----------
|
||||
|
||||
The PNG file is expected to be equal to the screen size. No scaling
|
||||
or tiling is supported.
|
@ -1,269 +0,0 @@
|
||||
/*
|
||||
* \brief Backdrop for Nitpicker
|
||||
* \author Norman Feske
|
||||
* \date 2009-08-28
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2009-2013 Genode Labs GmbH
|
||||
*
|
||||
* This file is part of the Genode OS framework, which is distributed
|
||||
* under the terms of the GNU General Public License version 2.
|
||||
*/
|
||||
|
||||
/* libpng includes */
|
||||
#include <png.h>
|
||||
|
||||
/* Genode includes */
|
||||
#include <nitpicker_session/connection.h>
|
||||
#include <framebuffer_session/client.h>
|
||||
#include <base/printf.h>
|
||||
#include <base/sleep.h>
|
||||
#include <util/misc_math.h>
|
||||
#include <os/config.h>
|
||||
|
||||
using namespace Genode;
|
||||
|
||||
|
||||
/***************
|
||||
** Dithering **
|
||||
***************/
|
||||
|
||||
enum { DITHER_SIZE = 16, DITHER_MASK = DITHER_SIZE - 1 };
|
||||
|
||||
static const int dither_matrix[DITHER_SIZE][DITHER_SIZE] = {
|
||||
{ 0,192, 48,240, 12,204, 60,252, 3,195, 51,243, 15,207, 63,255 },
|
||||
{ 128, 64,176,112,140, 76,188,124,131, 67,179,115,143, 79,191,127 },
|
||||
{ 32,224, 16,208, 44,236, 28,220, 35,227, 19,211, 47,239, 31,223 },
|
||||
{ 160, 96,144, 80,172,108,156, 92,163, 99,147, 83,175,111,159, 95 },
|
||||
{ 8,200, 56,248, 4,196, 52,244, 11,203, 59,251, 7,199, 55,247 },
|
||||
{ 136, 72,184,120,132, 68,180,116,139, 75,187,123,135, 71,183,119 },
|
||||
{ 40,232, 24,216, 36,228, 20,212, 43,235, 27,219, 39,231, 23,215 },
|
||||
{ 168,104,152, 88,164,100,148, 84,171,107,155, 91,167,103,151, 87 },
|
||||
{ 2,194, 50,242, 14,206, 62,254, 1,193, 49,241, 13,205, 61,253 },
|
||||
{ 130, 66,178,114,142, 78,190,126,129, 65,177,113,141, 77,189,125 },
|
||||
{ 34,226, 18,210, 46,238, 30,222, 33,225, 17,209, 45,237, 29,221 },
|
||||
{ 162, 98,146, 82,174,110,158, 94,161, 97,145, 81,173,109,157, 93 },
|
||||
{ 10,202, 58,250, 6,198, 54,246, 9,201, 57,249, 5,197, 53,245 },
|
||||
{ 138, 74,186,122,134, 70,182,118,137, 73,185,121,133, 69,181,117 },
|
||||
{ 42,234, 26,218, 38,230, 22,214, 41,233, 25,217, 37,229, 21,213 },
|
||||
{ 170,106,154, 90,166,102,150, 86,169,105,153, 89,165,101,149, 85 }
|
||||
};
|
||||
|
||||
|
||||
static inline uint16_t rgb565(int r, int g, int b)
|
||||
{
|
||||
enum {
|
||||
R_MASK = 0xf800, R_LSHIFT = 8,
|
||||
G_MASK = 0x07e0, G_LSHIFT = 3,
|
||||
B_MASK = 0x001f, B_RSHIFT = 3
|
||||
};
|
||||
return ((r << R_LSHIFT) & R_MASK)
|
||||
| ((g << G_LSHIFT) & G_MASK)
|
||||
| ((b >> B_RSHIFT) & B_MASK);
|
||||
}
|
||||
|
||||
|
||||
static void convert_line_rgba_to_rgb565(const unsigned char *rgba_src,
|
||||
uint16_t *dst, int num_pixels, int line)
|
||||
{
|
||||
enum { CHANNEL_MAX = 255 };
|
||||
|
||||
int const *dm = dither_matrix[line & DITHER_MASK];
|
||||
|
||||
for (int i = 0; i < num_pixels; i++) {
|
||||
int v = dm[i & DITHER_MASK] >> 5;
|
||||
|
||||
*dst++ = rgb565(min(v + (int)rgba_src[0], (int)CHANNEL_MAX),
|
||||
min(v + (int)rgba_src[1], (int)CHANNEL_MAX),
|
||||
min(v + (int)rgba_src[2], (int)CHANNEL_MAX));
|
||||
|
||||
/* we ignore the alpha channel */
|
||||
|
||||
rgba_src += 4; /* next pixel */
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/************************
|
||||
** PNG image decoding **
|
||||
************************/
|
||||
|
||||
class Png_stream
|
||||
{
|
||||
private:
|
||||
|
||||
char *_addr;
|
||||
|
||||
public:
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
Png_stream(char *addr) { _addr = addr; }
|
||||
|
||||
/**
|
||||
* Read from png stream
|
||||
*/
|
||||
void read(char *dst, int len)
|
||||
{
|
||||
Genode::memcpy(dst, _addr, len);
|
||||
_addr += len;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* PNG read callback
|
||||
*/
|
||||
static void user_read_data(png_structp png_ptr, png_bytep data, png_size_t len)
|
||||
{
|
||||
Png_stream *stream = (Png_stream *)png_get_io_ptr(png_ptr);
|
||||
|
||||
stream->read((char *)data, len);
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void convert_png_to_rgb565(void *png_data,
|
||||
uint16_t *dst, int dst_w, int dst_h)
|
||||
{
|
||||
Png_stream *stream = new (env()->heap()) Png_stream((char *)png_data);
|
||||
|
||||
png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, 0, 0, 0);
|
||||
if (!png_ptr) return;
|
||||
|
||||
png_set_read_fn(png_ptr, stream, user_read_data);
|
||||
|
||||
png_infop info_ptr = png_create_info_struct(png_ptr);
|
||||
if (!info_ptr) {
|
||||
png_destroy_read_struct(&png_ptr, png_infopp_NULL, png_infopp_NULL);
|
||||
return;
|
||||
}
|
||||
|
||||
png_read_info(png_ptr, info_ptr);
|
||||
|
||||
/* get image data chunk */
|
||||
int bit_depth, color_type, interlace_type;
|
||||
png_uint_32 img_w, img_h;
|
||||
png_get_IHDR(png_ptr, info_ptr, &img_w, &img_h, &bit_depth, &color_type,
|
||||
&interlace_type, int_p_NULL, int_p_NULL);
|
||||
printf("png is %d x %d, depth=%d\n", (int)img_w, (int)img_h, bit_depth);
|
||||
|
||||
if (color_type == PNG_COLOR_TYPE_PALETTE)
|
||||
png_set_palette_to_rgb(png_ptr);
|
||||
|
||||
if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8)
|
||||
png_set_gray_1_2_4_to_8(png_ptr);
|
||||
|
||||
if (color_type == PNG_COLOR_TYPE_GRAY || color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
|
||||
png_set_gray_to_rgb(png_ptr);
|
||||
|
||||
if (bit_depth < 8) png_set_packing(png_ptr);
|
||||
if (bit_depth == 16) png_set_strip_16(png_ptr);
|
||||
|
||||
/* allocate buffer for decoding a row */
|
||||
static png_byte *row_ptr;
|
||||
static int curr_row_size;
|
||||
|
||||
int needed_row_size = png_get_rowbytes(png_ptr, info_ptr)*8;
|
||||
|
||||
if (curr_row_size < needed_row_size) {
|
||||
if (row_ptr) env()->heap()->free(row_ptr, curr_row_size);
|
||||
row_ptr = (png_byte *)env()->heap()->alloc(needed_row_size);
|
||||
curr_row_size = needed_row_size;
|
||||
}
|
||||
|
||||
/* fill texture */
|
||||
int dst_y = 0;
|
||||
for (int j = 0; j < min((int)img_h, dst_h); j++, dst_y++) {
|
||||
png_read_row(png_ptr, row_ptr, NULL);
|
||||
convert_line_rgba_to_rgb565((unsigned char *)row_ptr, dst + dst_y*dst_w,
|
||||
min(dst_w, (int)img_w), j);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/****************************
|
||||
** Configuration handling **
|
||||
****************************/
|
||||
|
||||
/**
|
||||
* Determine PNG filename of image to be used as background
|
||||
*
|
||||
* \param dst destination buffer for storing the filename
|
||||
* \param dst_len size of destination buffer
|
||||
* \return 0 on success
|
||||
*/
|
||||
static int read_image_filename_from_config(char *dst, Genode::size_t dst_len)
|
||||
{
|
||||
try {
|
||||
Xml_node image_xml = config()->xml_node().sub_node("image");
|
||||
image_xml.value(dst, dst_len);
|
||||
return 0;
|
||||
} catch (Xml_node::Nonexistent_sub_node) {
|
||||
printf("Error: Configuration has no 'image' declaration.\n");
|
||||
return -2;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/******************
|
||||
** Main program **
|
||||
******************/
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
enum { PNG_NAME_MAX = 128 };
|
||||
static char png_name[PNG_NAME_MAX];
|
||||
|
||||
if (read_image_filename_from_config(png_name, sizeof(png_name)) < 0)
|
||||
return -1;
|
||||
|
||||
printf("using PNG file \"%s\" as background\n", png_name);
|
||||
|
||||
static void *png_data;
|
||||
try {
|
||||
static Rom_connection png_rom(png_name);
|
||||
png_data = env()->rm_session()->attach(png_rom.dataspace());
|
||||
} catch (...) {
|
||||
printf("Error: Could not obtain PNG image from ROM service\n");
|
||||
return -2;
|
||||
}
|
||||
|
||||
static Nitpicker::Connection nitpicker;
|
||||
|
||||
/* obtain physical screen size */
|
||||
Framebuffer::Mode const mode = nitpicker.mode();
|
||||
|
||||
/* setup virtual framebuffer mode */
|
||||
nitpicker.buffer(mode, false);
|
||||
|
||||
static Framebuffer::Session_client framebuffer(nitpicker.framebuffer_session());
|
||||
Nitpicker::Session::View_handle view_handle = nitpicker.create_view();
|
||||
|
||||
if (mode.format() != Framebuffer::Mode::RGB565) {
|
||||
printf("Error: Color mode %d not supported\n", (int)mode.format());
|
||||
return -3;
|
||||
}
|
||||
|
||||
/* make virtual framebuffer locally accessible */
|
||||
uint16_t *fb = env()->rm_session()->attach(framebuffer.dataspace());
|
||||
|
||||
/* fill virtual framebuffer with decoded image data */
|
||||
convert_png_to_rgb565(png_data, fb, mode.width(), mode.height());
|
||||
|
||||
/* display view behind all others */
|
||||
typedef Nitpicker::Session::Command Command;
|
||||
nitpicker.enqueue<Command::Background>(view_handle);
|
||||
Nitpicker::Rect rect(Nitpicker::Point(),
|
||||
Nitpicker::Area(mode.width(), mode.height()));
|
||||
nitpicker.enqueue<Command::Geometry>(view_handle, rect);
|
||||
nitpicker.enqueue<Command::To_back>(view_handle);
|
||||
nitpicker.execute();
|
||||
|
||||
framebuffer.refresh(0, 0, mode.width(), mode.height());
|
||||
|
||||
sleep_forever();
|
||||
return 0;
|
||||
}
|
@ -1,4 +0,0 @@
|
||||
TARGET = backdrop
|
||||
SRC_CC = main.cc
|
||||
LIBS = base libpng_static libz_static mini_c config
|
||||
CC_OPT += -DPNG_USER_CONFIG
|
@ -9,6 +9,7 @@ set build_components {
|
||||
server/nitpicker app/pointer server/report_rom
|
||||
drivers/framebuffer drivers/pci drivers/input
|
||||
test/nitpicker
|
||||
app/backdrop
|
||||
app/launchpad
|
||||
server/nit_fb
|
||||
}
|
||||
@ -153,34 +154,58 @@ append config {
|
||||
</any-service>
|
||||
</route>
|
||||
</start>
|
||||
<start name="testnit">
|
||||
<resource name="RAM" quantum="1M"/>
|
||||
<route>
|
||||
<any-service> <child name="wm"/> <parent/> <any-child/>
|
||||
</any-service>
|
||||
</route>
|
||||
</start>
|
||||
<start name="direct_testnit">
|
||||
<binary name="testnit" />
|
||||
<resource name="RAM" quantum="1M"/>
|
||||
<route>
|
||||
<any-service> <child name="nitpicker"/> <parent/> <any-child/>
|
||||
</any-service>
|
||||
</route>
|
||||
</start>
|
||||
<start name="launchpad">
|
||||
<resource name="RAM" quantum="20M"/>
|
||||
<config>
|
||||
<launcher name="testnit" ram_quota="768K" />
|
||||
<launcher name="nit_fb" ram_quota="7M">
|
||||
<config width="500" height="400" />
|
||||
</launcher>
|
||||
<launcher name="nitpicker" ram_quota="1M" >
|
||||
<config>
|
||||
<domain name="default" layer="2" />
|
||||
<policy label="" domain="default"/>
|
||||
</config>
|
||||
</launcher>
|
||||
<launcher name="testnit" ram_quota="768K" />
|
||||
</config>
|
||||
<route>
|
||||
<any-service> <child name="wm"/> <parent/> <any-child/>
|
||||
</any-service>
|
||||
</route>
|
||||
</start>
|
||||
<start name="nit_fb">
|
||||
<resource name="RAM" quantum="20M"/>
|
||||
<config width="400" height="300" />
|
||||
<start name="backdrop">
|
||||
<resource name="RAM" quantum="4M"/>
|
||||
<config>
|
||||
<libc>
|
||||
<vfs>
|
||||
<rom name="genode_logo.png"/>
|
||||
<rom name="grid.png"/>
|
||||
</vfs>
|
||||
</libc>
|
||||
<fill color="#224433" />
|
||||
<image png="grid.png" tiled="yes" alpha="200" />
|
||||
<image png="genode_logo.png" anchor="bottom_right" alpha="150"
|
||||
xpos="-20" ypos="-20" />
|
||||
</config>
|
||||
<route>
|
||||
<any-service> <child name="nitpicker"/> <parent/> <any-child/>
|
||||
</any-service>
|
||||
</route>
|
||||
</start>
|
||||
<start name="wm_backdrop">
|
||||
<binary name="backdrop" />
|
||||
<resource name="RAM" quantum="4M"/>
|
||||
<config>
|
||||
<libc>
|
||||
<vfs>
|
||||
<rom name="genode_logo.png"/>
|
||||
</vfs>
|
||||
</libc>
|
||||
<fill color="#664455" />
|
||||
<image png="genode_logo.png" scale="zoom" alpha="150" />
|
||||
<image png="genode_logo.png" scale="fit" alpha="150" tiled="yes" />
|
||||
<image png="genode_logo.png" />
|
||||
</config>
|
||||
<route>
|
||||
<any-service> <child name="wm"/> <parent/> <any-child/>
|
||||
</any-service>
|
||||
@ -190,6 +215,10 @@ append config {
|
||||
|
||||
install_config $config
|
||||
|
||||
# copy backdrop PNG images to bin directory
|
||||
foreach file { genode_logo.png grid.png } {
|
||||
file copy -force [genode_dir]/repos/gems/src/app/backdrop/$file bin/ }
|
||||
|
||||
|
||||
#
|
||||
# Boot modules
|
||||
@ -202,7 +231,10 @@ set boot_modules {
|
||||
wm decorator
|
||||
floating_window_layouter
|
||||
nitpicker pointer report_rom
|
||||
backdrop
|
||||
testnit launchpad nit_fb
|
||||
ld.lib.so libpng.lib.so libc.lib.so libm.lib.so zlib.lib.so
|
||||
genode_logo.png grid.png
|
||||
}
|
||||
|
||||
# platform-specific modules
|
||||
|
76
repos/gems/src/app/backdrop/README
Normal file
76
repos/gems/src/app/backdrop/README
Normal file
@ -0,0 +1,76 @@
|
||||
This directory contains a backdrop program for Nitpicker. It composes a
|
||||
background image out of a solid color and an arbitrary number of PNG image
|
||||
files. It is able to dynamically respond to configuration changes as well
|
||||
as a changed screen size.
|
||||
|
||||
|
||||
Configuration
|
||||
~~~~~~~~~~~~~
|
||||
|
||||
A typical example configuration looks as follows.
|
||||
|
||||
! <config>
|
||||
! <libc>
|
||||
! <vfs>
|
||||
! <rom name="genode_logo.png"/>
|
||||
! <rom name="grid.png"/>
|
||||
! </vfs>
|
||||
! </libc>
|
||||
! <fill color="#224433" />
|
||||
! <image png="grid.png" tiled="yes" alpha="200" />
|
||||
! <image png="genode_logo.png" anchor="bottom_right" alpha="150"
|
||||
! xpos="-20" ypos="-20" />
|
||||
! </config>
|
||||
|
||||
Backdrop obtains PNG images file from the libc VFS. In the example, the VFS is
|
||||
configured to present two ROM modules as files in the root directory. Those
|
||||
files are then referred to by the subsequent '<image>' nodes.
|
||||
|
||||
The final background image is generated by applying a number of graphical
|
||||
operations in the order of their appearance in the configuration. The
|
||||
'<fill>' operation fills the entire screen with the solid color as
|
||||
specified by the 'color' attribute. The default color is black.
|
||||
|
||||
The '<image>' operation loads a PNG image from the VFS, scales and positions
|
||||
it according to the '<image>' attributes, and paints it either as tiles
|
||||
covering the whole screen or as a single image. The supported attributes are
|
||||
|
||||
:tiled (default "no"):
|
||||
|
||||
If set to "yes", the image will be used as tile to cover the entire screen.
|
||||
|
||||
:alpha (default is opaque):
|
||||
|
||||
A number in the range of 0..255 that specifies the opacity of the image
|
||||
when painted.
|
||||
|
||||
:anchor (default "center"):
|
||||
|
||||
Defines the screen position that is used as a basis for positioning the
|
||||
image. Supported values are "top_left", "top", "top_right", "left",
|
||||
"center", "right", "bottom_left", "bottom", and "bottom_right".
|
||||
In the example above, the _genode_logo.png_ image will be positioned
|
||||
in the bottom-right corner of the screen.
|
||||
|
||||
:xpos and ypos (default "0"):
|
||||
|
||||
The 'xpos' and 'ypos' attributes define the position of the image relative
|
||||
to the anchor. It is meant for allowing the pixel-perfect fine tuning of
|
||||
positions.
|
||||
|
||||
:scale (no scaling by default):
|
||||
|
||||
The 'attribute' specifies the way of how the image should be adjusted to
|
||||
the screen size by the means of proportional scaling. Possible values are
|
||||
"fit" and "zoom". The former scales the image such that the entire image
|
||||
is visible on screen. The latter makes sure that the entire screen is
|
||||
filled with (a viewport of) the image. When using the "zoom" value, the
|
||||
viewport can be defined via the 'anchor', 'xpos', and 'ypos' attributes.
|
||||
|
||||
|
||||
Example
|
||||
~~~~~~~
|
||||
|
||||
Please refer to the _gems/run/wm.run_ script for a practical example of
|
||||
using the backdrop.
|
||||
|
62
repos/gems/src/app/backdrop/chunky_texture.h
Normal file
62
repos/gems/src/app/backdrop/chunky_texture.h
Normal file
@ -0,0 +1,62 @@
|
||||
/*
|
||||
* \brief Texture with backing store for pixels and alpha channel
|
||||
* \author Norman Feske
|
||||
* \date 2014-08-22
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2014 Genode Labs GmbH
|
||||
*
|
||||
* This file is part of the Genode OS framework, which is distributed
|
||||
* under the terms of the GNU General Public License version 2.
|
||||
*/
|
||||
|
||||
#ifndef _CHUNKY_TEXTURE_H_
|
||||
#define _CHUNKY_TEXTURE_H_
|
||||
|
||||
#include <os/surface.h>
|
||||
#include <os/attached_ram_dataspace.h>
|
||||
|
||||
template <typename PT>
|
||||
class Chunky_texture : Genode::Attached_ram_dataspace, public Genode::Texture<PT>
|
||||
{
|
||||
private:
|
||||
|
||||
typedef Genode::Surface_base::Area Area;
|
||||
|
||||
/**
|
||||
* Calculate memory needed to store the texture
|
||||
*/
|
||||
static Genode::size_t _num_bytes(Area size)
|
||||
{
|
||||
/* account for pixel size + 1 byte per alpha value */
|
||||
return size.count()*(sizeof(PT) + 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return base of pixel buffer
|
||||
*/
|
||||
PT *_pixel()
|
||||
{
|
||||
return local_addr<PT>();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return base of alpha buffer
|
||||
*/
|
||||
unsigned char *_alpha(Area size)
|
||||
{
|
||||
/* alpha buffer follows pixel buffer */
|
||||
return (unsigned char *)(local_addr<PT>() + size.count());
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
Chunky_texture(Genode::Ram_session &ram, Genode::Surface_base::Area size)
|
||||
:
|
||||
Genode::Attached_ram_dataspace(&ram, _num_bytes(size)),
|
||||
Genode::Texture<PT>(_pixel(), _alpha(size), size)
|
||||
{ }
|
||||
};
|
||||
|
||||
#endif /* _CHUNKY_TEXTURE_H_ */
|
55
repos/gems/src/app/backdrop/file.cc
Normal file
55
repos/gems/src/app/backdrop/file.cc
Normal file
@ -0,0 +1,55 @@
|
||||
/*
|
||||
* \brief Utility for loading a file
|
||||
* \author Norman Feske
|
||||
* \date 2014-08-14
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2014 Genode Labs GmbH
|
||||
*
|
||||
* This file is part of the Genode OS framework, which is distributed
|
||||
* under the terms of the GNU General Public License version 2.
|
||||
*/
|
||||
|
||||
/* Genode includes */
|
||||
#include <base/printf.h>
|
||||
|
||||
/* local includes */
|
||||
#include "file.h"
|
||||
|
||||
/* libc includes */
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
|
||||
|
||||
static Genode::size_t file_size(char const *name)
|
||||
{
|
||||
struct stat s;
|
||||
s.st_size = 0;
|
||||
stat(name, &s);
|
||||
return s.st_size;
|
||||
}
|
||||
|
||||
|
||||
File::File(char const *name, Genode::Allocator &alloc)
|
||||
:
|
||||
_alloc(alloc),
|
||||
_file_size(file_size(name)),
|
||||
_data(alloc.alloc(_file_size))
|
||||
{
|
||||
int const fd = open(name, O_RDONLY);
|
||||
if (read(fd, _data, _file_size) < 0) {
|
||||
PERR("reading from file \"%s\" failed (error %d)", name, errno);
|
||||
throw Reading_failed();
|
||||
}
|
||||
close(fd);
|
||||
}
|
||||
|
||||
|
||||
File::~File()
|
||||
{
|
||||
_alloc.free(_data, _file_size);
|
||||
}
|
50
repos/gems/src/app/backdrop/file.h
Normal file
50
repos/gems/src/app/backdrop/file.h
Normal file
@ -0,0 +1,50 @@
|
||||
/*
|
||||
* \brief Utility for loading a file
|
||||
* \author Norman Feske
|
||||
* \date 2014-08-14
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2014 Genode Labs GmbH
|
||||
*
|
||||
* This file is part of the Genode OS framework, which is distributed
|
||||
* under the terms of the GNU General Public License version 2.
|
||||
*/
|
||||
|
||||
#ifndef _FILE_H_
|
||||
#define _FILE_H_
|
||||
|
||||
/* Genode includes */
|
||||
#include <base/allocator.h>
|
||||
|
||||
class File
|
||||
{
|
||||
private:
|
||||
|
||||
Genode::Allocator &_alloc;
|
||||
Genode::size_t const _file_size;
|
||||
void *_data;
|
||||
|
||||
public:
|
||||
|
||||
/**
|
||||
* Exception type
|
||||
*/
|
||||
class Reading_failed { };
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* \throw Reading_failed;
|
||||
*/
|
||||
File(char const *name, Genode::Allocator &alloc);
|
||||
|
||||
~File();
|
||||
|
||||
template <typename T> T *data() { return (T *)_data; }
|
||||
|
||||
Genode::size_t size() const { return _file_size; }
|
||||
};
|
||||
|
||||
#endif /* _FILE_H_ */
|
||||
|
BIN
repos/gems/src/app/backdrop/genode_logo.png
Normal file
BIN
repos/gems/src/app/backdrop/genode_logo.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 19 KiB |
BIN
repos/gems/src/app/backdrop/grid.png
Normal file
BIN
repos/gems/src/app/backdrop/grid.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 582 B |
375
repos/gems/src/app/backdrop/main.cc
Normal file
375
repos/gems/src/app/backdrop/main.cc
Normal file
@ -0,0 +1,375 @@
|
||||
/*
|
||||
* \brief Backdrop for Nitpicker
|
||||
* \author Norman Feske
|
||||
* \date 2009-08-28
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2009-2014 Genode Labs GmbH
|
||||
*
|
||||
* This file is part of the Genode OS framework, which is distributed
|
||||
* under the terms of the GNU General Public License version 2.
|
||||
*/
|
||||
|
||||
/* Genode includes */
|
||||
#include <nitpicker_session/connection.h>
|
||||
#include <base/printf.h>
|
||||
#include <util/misc_math.h>
|
||||
#include <os/config.h>
|
||||
#include <decorator/xml_utils.h>
|
||||
#include <nitpicker_gfx/box_painter.h>
|
||||
#include <nitpicker_gfx/texture_painter.h>
|
||||
#include <os/attached_dataspace.h>
|
||||
#include <util/volatile_object.h>
|
||||
#include <os/pixel_rgb565.h>
|
||||
#include <os/pixel_rgb888.h>
|
||||
|
||||
/* local includes */
|
||||
#include "png_image.h"
|
||||
#include "file.h"
|
||||
#include "xml_anchor.h"
|
||||
#include "texture_utils.h"
|
||||
|
||||
using namespace Genode;
|
||||
|
||||
|
||||
namespace Backdrop { struct Main; }
|
||||
|
||||
|
||||
struct Backdrop::Main
|
||||
{
|
||||
Nitpicker::Connection nitpicker;
|
||||
|
||||
struct Buffer
|
||||
{
|
||||
Nitpicker::Connection &nitpicker;
|
||||
|
||||
/* physical screen size */
|
||||
Framebuffer::Mode const mode = nitpicker.mode();
|
||||
|
||||
/**
|
||||
* Return dataspace capability for virtual framebuffer
|
||||
*/
|
||||
Dataspace_capability _ds_cap(Nitpicker::Connection &nitpicker)
|
||||
{
|
||||
/* setup virtual framebuffer mode */
|
||||
nitpicker.buffer(mode, false);
|
||||
|
||||
if (mode.format() != Framebuffer::Mode::RGB565) {
|
||||
PWRN("Color mode %d not supported\n", (int)mode.format());
|
||||
return Dataspace_capability();
|
||||
}
|
||||
|
||||
return nitpicker.framebuffer()->dataspace();
|
||||
}
|
||||
|
||||
Attached_dataspace fb_ds { _ds_cap(nitpicker) };
|
||||
|
||||
size_t surface_num_bytes() const
|
||||
{
|
||||
return size().count()*mode.bytes_per_pixel();
|
||||
}
|
||||
|
||||
Attached_ram_dataspace surface_ds { env()->ram_session(), surface_num_bytes() };
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
Buffer(Nitpicker::Connection &nitpicker) : nitpicker(nitpicker) { }
|
||||
|
||||
/**
|
||||
* Return size of virtual framebuffer
|
||||
*/
|
||||
Surface_base::Area size() const
|
||||
{
|
||||
return Surface_base::Area(mode.width(), mode.height());
|
||||
}
|
||||
|
||||
/**
|
||||
* Return back buffer as painting surface
|
||||
*/
|
||||
template <typename PT>
|
||||
Surface<PT> surface()
|
||||
{
|
||||
return Surface<PT>(surface_ds.local_addr<PT>(), size());
|
||||
}
|
||||
|
||||
void flush_surface()
|
||||
{
|
||||
/* blit back to front buffer */
|
||||
blit(surface_ds.local_addr<void>(), surface_num_bytes(),
|
||||
fb_ds.local_addr<void>(), surface_num_bytes(), surface_num_bytes(), 1);
|
||||
}
|
||||
};
|
||||
|
||||
Lazy_volatile_object<Buffer> buffer;
|
||||
|
||||
Nitpicker::Session::View_handle view_handle = nitpicker.create_view();
|
||||
|
||||
void _update_view()
|
||||
{
|
||||
/* display view behind all others */
|
||||
typedef Nitpicker::Session::Command Command;
|
||||
nitpicker.enqueue<Command::Background>(view_handle);
|
||||
Nitpicker::Rect rect(Nitpicker::Point(), buffer->size());
|
||||
nitpicker.enqueue<Command::Geometry>(view_handle, rect);
|
||||
nitpicker.enqueue<Command::To_back>(view_handle);
|
||||
nitpicker.execute();
|
||||
}
|
||||
|
||||
Signal_receiver &sig_rec;
|
||||
|
||||
/**
|
||||
* Function called on config change or mode change
|
||||
*/
|
||||
void handle_config(unsigned);
|
||||
|
||||
Signal_dispatcher<Main> config_dispatcher = {
|
||||
sig_rec, *this, &Main::handle_config};
|
||||
|
||||
void handle_sync(unsigned);
|
||||
|
||||
Signal_dispatcher<Main> sync_dispatcher = {
|
||||
sig_rec, *this, &Main::handle_sync};
|
||||
|
||||
template <typename PT>
|
||||
void paint_texture(Surface<PT> &, Texture<PT> const &, Surface_base::Point, bool);
|
||||
|
||||
void apply_image(Xml_node);
|
||||
void apply_fill(Xml_node);
|
||||
|
||||
Main(Signal_receiver &sig_rec) : sig_rec(sig_rec)
|
||||
{
|
||||
/* trigger application of initial config */
|
||||
Signal_transmitter(config_dispatcher).submit();
|
||||
|
||||
nitpicker.mode_sigh(config_dispatcher);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Calculate designated image size with proportional scaling applied
|
||||
*/
|
||||
static Surface_base::Area calc_scaled_size(Xml_node operation,
|
||||
Surface_base::Area image_size,
|
||||
Surface_base::Area mode_size)
|
||||
{
|
||||
char const *attr = "scale";
|
||||
if (!operation.has_attribute(attr))
|
||||
return image_size;
|
||||
|
||||
/* prevent division by zero, below */
|
||||
if (image_size.count() == 0)
|
||||
return image_size;
|
||||
|
||||
/*
|
||||
* Determine scale ratio (in 16.16 fixpoint format)
|
||||
*/
|
||||
unsigned const ratio =
|
||||
operation.attribute(attr).has_value("fit") ?
|
||||
min((mode_size.w() << 16) / image_size.w(),
|
||||
(mode_size.h() << 16) / image_size.h()) :
|
||||
operation.attribute(attr).has_value("zoom") ?
|
||||
max((mode_size.w() << 16) / image_size.w(),
|
||||
(mode_size.h() << 16) / image_size.h()) :
|
||||
1 << 16;
|
||||
|
||||
/*
|
||||
* We add 0.5 (1 << 15) to round instead of truncating the fractional
|
||||
* part when converting the fixpoint numbers to integers.
|
||||
*/
|
||||
return Surface_base::Area((image_size.w()*ratio + (1 << 15)) >> 16,
|
||||
(image_size.h()*ratio + (1 << 15)) >> 16);
|
||||
}
|
||||
|
||||
|
||||
template <typename PT>
|
||||
void Backdrop::Main::paint_texture(Surface<PT> &surface, Texture<PT> const &texture,
|
||||
Surface_base::Point pos, bool tiled)
|
||||
{
|
||||
/* prevent division by zero */
|
||||
if (texture.size().count() == 0)
|
||||
return;
|
||||
|
||||
if (tiled) {
|
||||
|
||||
/* shortcuts */
|
||||
int const w = texture.size().w(), surface_w = surface.size().w();
|
||||
int const h = texture.size().h(), surface_h = surface.size().h();
|
||||
|
||||
/* draw tiles across the whole surface */
|
||||
for (int y = (pos.y() % h) - h; y < surface_h + h; y += h)
|
||||
for (int x = (pos.x() % w) - w; x < surface_w + w; x += w)
|
||||
Texture_painter::paint(surface, texture, Color(),
|
||||
Texture_painter::Point(x, y),
|
||||
Texture_painter::SOLID,
|
||||
true);
|
||||
|
||||
} else {
|
||||
|
||||
Texture_painter::paint(surface, texture, Color(), pos,
|
||||
Texture_painter::SOLID, true);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Backdrop::Main::apply_image(Xml_node operation)
|
||||
{
|
||||
typedef Surface_base::Point Point;
|
||||
typedef Surface_base::Area Area;
|
||||
|
||||
if (!operation.has_attribute("png")) {
|
||||
PWRN("missing 'png' attribute in <image> node");
|
||||
return;
|
||||
}
|
||||
|
||||
char png_file_name[256];
|
||||
png_file_name[0] = 0;
|
||||
operation.attribute("png").value(png_file_name, sizeof(png_file_name));
|
||||
|
||||
File file(png_file_name, *env()->heap());
|
||||
|
||||
Anchor anchor(operation);
|
||||
|
||||
Png_image png_image(file.data<void>());
|
||||
|
||||
Area const scaled_size = calc_scaled_size(operation, png_image.size(),
|
||||
Area(buffer->mode.width(),
|
||||
buffer->mode.height()));
|
||||
/*
|
||||
* Determine parameters of graphics operation
|
||||
*/
|
||||
int const h_gap = (int)buffer->mode.width() - scaled_size.w(),
|
||||
v_gap = (int)buffer->mode.height() - scaled_size.h();
|
||||
|
||||
int const anchored_xpos = anchor.horizontal == Anchor::LOW ? 0
|
||||
: anchor.horizontal == Anchor::CENTER ? h_gap/2
|
||||
: anchor.horizontal == Anchor::HIGH ? h_gap
|
||||
: 0;
|
||||
|
||||
int const anchored_ypos = anchor.vertical == Anchor::LOW ? 0
|
||||
: anchor.vertical == Anchor::CENTER ? v_gap/2
|
||||
: anchor.vertical == Anchor::HIGH ? v_gap
|
||||
: 0;
|
||||
|
||||
Point const offset = Decorator::point_attribute(operation);
|
||||
|
||||
Point const pos = Point(anchored_xpos, anchored_ypos) + offset;
|
||||
|
||||
bool const tiled = operation.has_attribute("tiled")
|
||||
&& operation.attribute("tiled").has_value("yes");
|
||||
|
||||
unsigned alpha = Decorator::attribute(operation, "alpha", 256U);
|
||||
|
||||
/* obtain texture containing the pixels of the PNG image */
|
||||
Texture<Pixel_rgb888> *png_texture = png_image.texture<Pixel_rgb888>();
|
||||
|
||||
/* create texture with the scaled image */
|
||||
Chunky_texture<Pixel_rgb888> scaled_texture(*env()->ram_session(), scaled_size);
|
||||
scale(*png_texture, scaled_texture);
|
||||
|
||||
png_image.release_texture(png_texture);
|
||||
|
||||
/*
|
||||
* Code specific for the screen mode's pixel format
|
||||
*/
|
||||
|
||||
/* create texture with down-sampled scaled image */
|
||||
typedef Pixel_rgb565 PT;
|
||||
Chunky_texture<PT> texture(*env()->ram_session(), scaled_size);
|
||||
convert_pixel_format(scaled_texture, texture, alpha);
|
||||
|
||||
/* paint texture onto surface */
|
||||
Surface<PT> surface = buffer->surface<PT>();
|
||||
paint_texture(surface, texture, pos, tiled);
|
||||
}
|
||||
|
||||
|
||||
void Backdrop::Main::apply_fill(Xml_node operation)
|
||||
{
|
||||
/*
|
||||
* Code specific for the screen mode's pixel format
|
||||
*/
|
||||
|
||||
/* create texture with down-sampled scaled image */
|
||||
typedef Pixel_rgb565 PT;
|
||||
|
||||
Surface<PT> surface = buffer->surface<PT>();
|
||||
|
||||
Color const color = Decorator::attribute(operation, "color", Color(0, 0, 0));
|
||||
|
||||
Box_painter::paint(surface, Surface_base::Rect(Surface_base::Point(0, 0),
|
||||
buffer->size()), color);
|
||||
}
|
||||
|
||||
|
||||
void Backdrop::Main::handle_config(unsigned)
|
||||
{
|
||||
config()->reload();
|
||||
|
||||
buffer.construct(nitpicker);
|
||||
|
||||
/* clear surface */
|
||||
apply_fill(Xml_node("<fill color=\"#000000\"/>"));
|
||||
|
||||
/* apply graphics primitives defined in the config */
|
||||
try {
|
||||
for (unsigned i = 0; i < config()->xml_node().num_sub_nodes(); i++) {
|
||||
try {
|
||||
Xml_node operation = config()->xml_node().sub_node(i);
|
||||
|
||||
if (operation.has_type("image"))
|
||||
apply_image(operation);
|
||||
|
||||
if (operation.has_type("fill"))
|
||||
apply_fill(operation);
|
||||
}
|
||||
catch (...) {
|
||||
/*
|
||||
* Ignore failure of individual operation, i.e., non-existing
|
||||
* files or malformed PNG data.
|
||||
*/
|
||||
}
|
||||
}
|
||||
} catch (...) { /* ignore failure to obtain config */ }
|
||||
|
||||
/* schedule buffer refresh */
|
||||
nitpicker.framebuffer()->sync_sigh(sync_dispatcher);
|
||||
}
|
||||
|
||||
|
||||
void Backdrop::Main::handle_sync(unsigned)
|
||||
{
|
||||
buffer->flush_surface();
|
||||
_update_view();
|
||||
|
||||
/* disable sync signal until the next call of 'handle_config' */
|
||||
nitpicker.framebuffer()->sync_sigh(Signal_context_capability());
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Silence debug messages
|
||||
*/
|
||||
extern "C" void _sigprocmask() { }
|
||||
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
static Signal_receiver sig_rec;
|
||||
|
||||
static Backdrop::Main application(sig_rec);
|
||||
|
||||
/* process incoming signals */
|
||||
for (;;) {
|
||||
using namespace Genode;
|
||||
|
||||
Signal sig = sig_rec.wait_for_signal();
|
||||
Signal_dispatcher_base *dispatcher =
|
||||
dynamic_cast<Signal_dispatcher_base *>(sig.context());
|
||||
|
||||
if (dispatcher)
|
||||
dispatcher->dispatch(sig.num());
|
||||
}
|
||||
}
|
181
repos/gems/src/app/backdrop/png_image.h
Normal file
181
repos/gems/src/app/backdrop/png_image.h
Normal file
@ -0,0 +1,181 @@
|
||||
/*
|
||||
* \brief Utility for reading PNG images
|
||||
* \author Norman Feske
|
||||
* \date 2014-08-14
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2014 Genode Labs GmbH
|
||||
*
|
||||
* This file is part of the Genode OS framework, which is distributed
|
||||
* under the terms of the GNU General Public License version 2.
|
||||
*/
|
||||
|
||||
#ifndef _PNG_IMAGE_H_
|
||||
#define _PNG_IMAGE_H_
|
||||
|
||||
/* Genode includes */
|
||||
#include <os/texture.h>
|
||||
|
||||
/* libpng include */
|
||||
#include <png.h>
|
||||
|
||||
/* local includes */
|
||||
#include "chunky_texture.h"
|
||||
#include "texture_utils.h"
|
||||
|
||||
class Png_image
|
||||
{
|
||||
public:
|
||||
|
||||
/**
|
||||
* Exception types
|
||||
*/
|
||||
class Read_struct_failed { };
|
||||
class Info_failed { };
|
||||
|
||||
private:
|
||||
|
||||
template <typename EXC, typename T>
|
||||
static T _assert_non_null(T && arg)
|
||||
{
|
||||
if (!arg)
|
||||
throw EXC();
|
||||
|
||||
return arg;
|
||||
};
|
||||
|
||||
struct Read_struct
|
||||
{
|
||||
/* start of PNG data */
|
||||
png_bytep const data;
|
||||
|
||||
/* read position, maintained by 'read_callback' */
|
||||
unsigned pos = 0;
|
||||
|
||||
static void callback(png_structp png_ptr, png_bytep dst, png_size_t len)
|
||||
{
|
||||
Png_image *png = (Png_image *)png_get_io_ptr(png_ptr);
|
||||
Genode::memcpy(dst, png->_read_struct.data + png->_read_struct.pos, len);
|
||||
png->_read_struct.pos += len;
|
||||
}
|
||||
|
||||
png_structp png_ptr =
|
||||
_assert_non_null<Read_struct_failed>(
|
||||
png_create_read_struct(PNG_LIBPNG_VER_STRING, 0, 0, 0));
|
||||
|
||||
Read_struct(void *data) : data((png_bytep)data)
|
||||
{
|
||||
png_set_read_fn(png_ptr, this, callback);
|
||||
}
|
||||
|
||||
~Read_struct()
|
||||
{
|
||||
png_destroy_read_struct(&png_ptr, nullptr, nullptr);
|
||||
}
|
||||
};
|
||||
|
||||
Read_struct _read_struct;
|
||||
|
||||
struct Info
|
||||
{
|
||||
png_structp png_ptr;
|
||||
png_infop info_ptr;
|
||||
|
||||
int bit_depth, color_type, interlace_type;
|
||||
png_uint_32 img_w, img_h;
|
||||
|
||||
Info(png_structp png_ptr)
|
||||
:
|
||||
png_ptr(png_ptr),
|
||||
info_ptr(_assert_non_null<Info_failed>(png_create_info_struct(png_ptr)))
|
||||
{
|
||||
png_read_info(png_ptr, info_ptr);
|
||||
|
||||
png_get_IHDR(png_ptr, info_ptr, &img_w, &img_h, &bit_depth, &color_type,
|
||||
&interlace_type, nullptr, nullptr);
|
||||
|
||||
if (color_type == PNG_COLOR_TYPE_PALETTE)
|
||||
png_set_palette_to_rgb(png_ptr);
|
||||
|
||||
if (color_type == PNG_COLOR_TYPE_GRAY || color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
|
||||
png_set_gray_to_rgb(png_ptr);
|
||||
|
||||
if (bit_depth < 8) png_set_packing(png_ptr);
|
||||
if (bit_depth == 16) png_set_strip_16(png_ptr);
|
||||
}
|
||||
|
||||
~Info()
|
||||
{
|
||||
png_destroy_info_struct(png_ptr, &info_ptr);
|
||||
}
|
||||
|
||||
} _info { _read_struct.png_ptr };
|
||||
|
||||
struct Row
|
||||
{
|
||||
size_t const row_num_bytes;
|
||||
png_bytep const row_ptr;
|
||||
|
||||
Row(png_structp png_ptr, png_infop info_ptr)
|
||||
:
|
||||
row_num_bytes(png_get_rowbytes(png_ptr, info_ptr)*8),
|
||||
row_ptr((png_bytep)Genode::env()->heap()->alloc(row_num_bytes))
|
||||
{ }
|
||||
|
||||
~Row()
|
||||
{
|
||||
Genode::env()->heap()->free(row_ptr, row_num_bytes);
|
||||
}
|
||||
} _row { _read_struct.png_ptr, _info.info_ptr };
|
||||
|
||||
public:
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* \throw Read_struct_failed
|
||||
* \throw Info_failed
|
||||
*/
|
||||
Png_image(void *data) : _read_struct(data) { }
|
||||
|
||||
/**
|
||||
* Return size of PNG image
|
||||
*/
|
||||
Genode::Surface_base::Area size() const
|
||||
{
|
||||
return Genode::Surface_base::Area(_info.img_w, _info.img_h);
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtain PNG image as texture
|
||||
*/
|
||||
template <typename PT>
|
||||
Genode::Texture<PT> *texture()
|
||||
{
|
||||
Genode::Texture<PT> *texture = new (Genode::env()->heap())
|
||||
Chunky_texture<PT>(*Genode::env()->ram_session(), size());
|
||||
|
||||
/* fill texture with PNG image data */
|
||||
for (unsigned i = 0; i < size().h(); i++) {
|
||||
png_read_row(_read_struct.png_ptr, _row.row_ptr, NULL);
|
||||
texture->rgba((unsigned char *)_row.row_ptr, size().w()*4, i);
|
||||
}
|
||||
|
||||
return texture;
|
||||
}
|
||||
|
||||
/**
|
||||
* Free texture obtained via 'texture()'
|
||||
*/
|
||||
template <typename PT>
|
||||
void release_texture(Genode::Texture<PT> *texture)
|
||||
{
|
||||
Chunky_texture<PT> *chunky_texture =
|
||||
static_cast<Chunky_texture<PT> *>(texture);
|
||||
|
||||
Genode::destroy(Genode::env()->heap(), chunky_texture);
|
||||
}
|
||||
};
|
||||
|
||||
#endif /* _PNG_IMAGE_H_ */
|
3
repos/gems/src/app/backdrop/target.mk
Normal file
3
repos/gems/src/app/backdrop/target.mk
Normal file
@ -0,0 +1,3 @@
|
||||
TARGET = backdrop
|
||||
SRC_CC = main.cc file.cc texture.cc
|
||||
LIBS = base config libc libpng zlib blit
|
79
repos/gems/src/app/backdrop/texture.cc
Normal file
79
repos/gems/src/app/backdrop/texture.cc
Normal file
@ -0,0 +1,79 @@
|
||||
/*
|
||||
* \brief Support for Genode::Texture
|
||||
* \author Norman Feske
|
||||
* \date 2014-08-14
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2014 Genode Labs GmbH
|
||||
*
|
||||
* This file is part of the Genode OS framework, which is distributed
|
||||
* under the terms of the GNU General Public License version 2.
|
||||
*/
|
||||
|
||||
/* Genode includes */
|
||||
#include <os/texture.h>
|
||||
#include <os/pixel_rgb565.h>
|
||||
#include <os/pixel_rgb888.h>
|
||||
#include <util/dither_matrix.h>
|
||||
|
||||
namespace Genode {
|
||||
|
||||
template <>
|
||||
void
|
||||
Texture<Pixel_rgb565>::rgba(unsigned char const *rgba, unsigned len, int y)
|
||||
{
|
||||
if (len > size().w()) len = size().w();
|
||||
if (y < 0 || y >= (int)size().h()) return;
|
||||
|
||||
Pixel_rgb565 *dst_pixel = pixel() + y*size().w();
|
||||
unsigned char *dst_alpha = alpha() ? alpha() + y*size().w() : 0;
|
||||
|
||||
Dither_matrix::Row dither_row = Dither_matrix::row(y);
|
||||
|
||||
for (unsigned i = 0; i < len; i++) {
|
||||
|
||||
int v = dither_row.value(i) >> 5;
|
||||
int r = *rgba++ + v;
|
||||
int g = *rgba++ + v;
|
||||
int b = *rgba++ + v;
|
||||
int a = *rgba++;
|
||||
|
||||
if (a) a += v;
|
||||
|
||||
dst_pixel[i].rgba(min(r, 255), min(g, 255), min(b, 255));
|
||||
|
||||
if (dst_alpha)
|
||||
dst_alpha[i] = min(a, 255);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
template <>
|
||||
void
|
||||
Texture<Pixel_rgb888>::rgba(unsigned char const *rgba, unsigned len, int y)
|
||||
{
|
||||
if (len > size().w()) len = size().w();
|
||||
if (y < 0 || y >= (int)size().h()) return;
|
||||
|
||||
Pixel_rgb888 *dst_pixel = pixel() + y*size().w();
|
||||
unsigned char *dst_alpha = alpha() ? alpha() + y*size().w() : 0;
|
||||
|
||||
for (unsigned i = 0; i < len; i++) {
|
||||
|
||||
int r = *rgba++;
|
||||
int g = *rgba++;
|
||||
int b = *rgba++;
|
||||
int a = *rgba++;
|
||||
|
||||
dst_pixel[i].rgba(r, g, b);
|
||||
|
||||
if (dst_alpha)
|
||||
dst_alpha[i] = min(a, 255);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
template class Genode::Texture<Genode::Pixel_rgb565>;
|
||||
template class Genode::Texture<Genode::Pixel_rgb888>;
|
97
repos/gems/src/app/backdrop/texture_utils.h
Normal file
97
repos/gems/src/app/backdrop/texture_utils.h
Normal file
@ -0,0 +1,97 @@
|
||||
/*
|
||||
* \brief Utilities for working with textures
|
||||
* \author Norman Feske
|
||||
* \date 2014-08-21
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2014 Genode Labs GmbH
|
||||
*
|
||||
* This file is part of the Genode OS framework, which is distributed
|
||||
* under the terms of the GNU General Public License version 2.
|
||||
*/
|
||||
|
||||
#ifndef _TEXTURE_UTILS_H_
|
||||
#define _TEXTURE_UTILS_H_
|
||||
|
||||
#include <os/texture.h>
|
||||
|
||||
template <typename PT>
|
||||
static void scale(Genode::Texture<PT> const &src, Genode::Texture<PT> &dst)
|
||||
{
|
||||
/* sanity check to prevent division by zero */
|
||||
if (dst.size().count() == 0)
|
||||
return;
|
||||
|
||||
Genode::size_t const row_num_bytes = dst.size().w()*4;
|
||||
unsigned char *row = (unsigned char *)Genode::env()->heap()->alloc(row_num_bytes);
|
||||
|
||||
unsigned const mx = (src.size().w() << 16) / dst.size().w();
|
||||
unsigned const my = (src.size().h() << 16) / dst.size().h();
|
||||
|
||||
for (unsigned y = 0, src_y = 0; y < dst.size().h(); y++, src_y += my) {
|
||||
|
||||
unsigned const src_line_offset = src.size().w()*(src_y >> 16);
|
||||
|
||||
PT const *pixel_line = src.pixel() + src_line_offset;
|
||||
unsigned char const *alpha_line = src.alpha() + src_line_offset;
|
||||
|
||||
unsigned char *d = row;
|
||||
for (unsigned x = 0, src_x = 0; x < dst.size().w(); x++, src_x += mx) {
|
||||
|
||||
unsigned const pixel_offset = src_x >> 16;
|
||||
|
||||
PT const pixel = pixel_line[pixel_offset];
|
||||
unsigned char const alpha = alpha_line[pixel_offset];
|
||||
|
||||
*d++ = pixel.r();
|
||||
*d++ = pixel.g();
|
||||
*d++ = pixel.b();
|
||||
*d++ = alpha;
|
||||
}
|
||||
|
||||
dst.rgba(row, dst.size().w(), y);
|
||||
}
|
||||
|
||||
Genode::env()->heap()->free(row, row_num_bytes);
|
||||
}
|
||||
|
||||
|
||||
template <typename SRC_PT, typename DST_PT>
|
||||
static void convert_pixel_format(Genode::Texture<SRC_PT> const &src,
|
||||
Genode::Texture<DST_PT> &dst,
|
||||
unsigned alpha)
|
||||
{
|
||||
/* sanity check */
|
||||
if (src.size() != dst.size())
|
||||
return;
|
||||
|
||||
Genode::size_t const row_num_bytes = dst.size().w()*4;
|
||||
unsigned char *row = (unsigned char *)Genode::env()->heap()->alloc(row_num_bytes);
|
||||
|
||||
/* shortcuts */
|
||||
unsigned const w = dst.size().w(), h = dst.size().h();
|
||||
|
||||
for (unsigned y = 0, line_offset = 0; y < h; y++, line_offset += w) {
|
||||
|
||||
SRC_PT const *src_pixel = src.pixel() + line_offset;
|
||||
unsigned char const *src_alpha = src.alpha() + line_offset;
|
||||
|
||||
/* fill row buffer with values from source texture */
|
||||
unsigned char *d = row;
|
||||
for (unsigned x = 0; x < w; x++, src_pixel++, src_alpha++) {
|
||||
|
||||
*d++ = src_pixel->r();
|
||||
*d++ = src_pixel->g();
|
||||
*d++ = src_pixel->b();
|
||||
*d++ = (*src_alpha * alpha) >> 8;
|
||||
}
|
||||
|
||||
/* assign row to destination texture */
|
||||
dst.rgba(row, w, y);
|
||||
}
|
||||
|
||||
Genode::env()->heap()->free(row, row_num_bytes);
|
||||
}
|
||||
|
||||
#endif /* _TEXTURE_UTILS_H_ */
|
71
repos/gems/src/app/backdrop/xml_anchor.h
Normal file
71
repos/gems/src/app/backdrop/xml_anchor.h
Normal file
@ -0,0 +1,71 @@
|
||||
/*
|
||||
* \brief Utility for parsing an anchor attribute from an XML node
|
||||
* \author Norman Feske
|
||||
* \date 2014-08-21
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2014 Genode Labs GmbH
|
||||
*
|
||||
* This file is part of the Genode OS framework, which is distributed
|
||||
* under the terms of the GNU General Public License version 2.
|
||||
*/
|
||||
|
||||
#ifndef _XML_ANCHOR_H_
|
||||
#define _XML_ANCHOR_H_
|
||||
|
||||
#include <util/xml_node.h>
|
||||
|
||||
class Anchor
|
||||
{
|
||||
public:
|
||||
|
||||
enum Direction { LOW, CENTER, HIGH };
|
||||
|
||||
Direction horizontal = CENTER, vertical = CENTER;
|
||||
|
||||
private:
|
||||
|
||||
typedef Genode::Xml_node Xml_node;
|
||||
|
||||
struct Value
|
||||
{
|
||||
char const *value;
|
||||
Direction horizontal, vertical;
|
||||
};
|
||||
|
||||
Value const _values[10] = { { "top_left", LOW, LOW },
|
||||
{ "top", CENTER, LOW },
|
||||
{ "top_right", HIGH, LOW },
|
||||
{ "left", LOW, CENTER },
|
||||
{ "center", CENTER, CENTER },
|
||||
{ "right", HIGH, CENTER },
|
||||
{ "bottom_left", LOW, HIGH },
|
||||
{ "bottom", CENTER, HIGH },
|
||||
{ "bottom_right", HIGH, HIGH },
|
||||
{ nullptr, CENTER, CENTER } };
|
||||
|
||||
public:
|
||||
|
||||
Anchor(Xml_node node)
|
||||
{
|
||||
char const * const attr = "anchor";
|
||||
|
||||
if (!node.has_attribute(attr))
|
||||
return;
|
||||
|
||||
Xml_node::Attribute const anchor = node.attribute(attr);
|
||||
|
||||
for (Value const *value = _values; value->value; value++) {
|
||||
if (anchor.has_value(value->value)) {
|
||||
horizontal = value->horizontal;
|
||||
vertical = value->vertical;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
PWRN("unsupported anchor attribute value");
|
||||
}
|
||||
};
|
||||
|
||||
#endif /* _XML_ANCHOR_H_ */
|
Loading…
Reference in New Issue
Block a user