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
|
server/nitpicker app/pointer server/report_rom
|
||||||
drivers/framebuffer drivers/pci drivers/input
|
drivers/framebuffer drivers/pci drivers/input
|
||||||
test/nitpicker
|
test/nitpicker
|
||||||
|
app/backdrop
|
||||||
app/launchpad
|
app/launchpad
|
||||||
server/nit_fb
|
server/nit_fb
|
||||||
}
|
}
|
||||||
@ -153,34 +154,58 @@ append config {
|
|||||||
</any-service>
|
</any-service>
|
||||||
</route>
|
</route>
|
||||||
</start>
|
</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">
|
<start name="launchpad">
|
||||||
<resource name="RAM" quantum="20M"/>
|
<resource name="RAM" quantum="20M"/>
|
||||||
<config>
|
<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>
|
</config>
|
||||||
<route>
|
<route>
|
||||||
<any-service> <child name="wm"/> <parent/> <any-child/>
|
<any-service> <child name="wm"/> <parent/> <any-child/>
|
||||||
</any-service>
|
</any-service>
|
||||||
</route>
|
</route>
|
||||||
</start>
|
</start>
|
||||||
<start name="nit_fb">
|
<start name="backdrop">
|
||||||
<resource name="RAM" quantum="20M"/>
|
<resource name="RAM" quantum="4M"/>
|
||||||
<config width="400" height="300" />
|
<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>
|
<route>
|
||||||
<any-service> <child name="wm"/> <parent/> <any-child/>
|
<any-service> <child name="wm"/> <parent/> <any-child/>
|
||||||
</any-service>
|
</any-service>
|
||||||
@ -190,6 +215,10 @@ append config {
|
|||||||
|
|
||||||
install_config $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
|
# Boot modules
|
||||||
@ -202,7 +231,10 @@ set boot_modules {
|
|||||||
wm decorator
|
wm decorator
|
||||||
floating_window_layouter
|
floating_window_layouter
|
||||||
nitpicker pointer report_rom
|
nitpicker pointer report_rom
|
||||||
|
backdrop
|
||||||
testnit launchpad nit_fb
|
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
|
# 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