mirror of
https://github.com/genodelabs/genode.git
synced 2025-04-07 11:27:29 +00:00
Polygon drawing and rudimentary 3D routines
This patch adds two new painters located at gems/include/polygon_gfx. Both painters draw convex polygons with an arbirary number of points. The shaded-polygon painter interpolates the color and alpha values whereas the textured-polygon painter applies a texture to the polygon. The painters are accompanied by simplistic 3D routines located at gems/include/nano3d/ and a corresponding example (gems/run/nano3d.run).
This commit is contained in:
parent
c74a4fbbe2
commit
259b127f96
69
repos/gems/include/nano3d/cube_shape.h
Normal file
69
repos/gems/include/nano3d/cube_shape.h
Normal file
@ -0,0 +1,69 @@
|
||||
/*
|
||||
* \brief Cube 3D object
|
||||
* \author Norman Feske
|
||||
* \date 2015-06-19
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2015 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 _INCLUDE__NANO3D__CUBE_SHAPE_H_
|
||||
#define _INCLUDE__NANO3D__CUBE_SHAPE_H_
|
||||
|
||||
#include <nano3d/vertex_array.h>
|
||||
|
||||
namespace Nano3d { class Cube_shape; }
|
||||
|
||||
|
||||
class Nano3d::Cube_shape
|
||||
{
|
||||
private:
|
||||
|
||||
enum { NUM_VERTICES = 8, NUM_FACES = 6 };
|
||||
|
||||
typedef Nano3d::Vertex_array<NUM_VERTICES> Vertex_array;
|
||||
|
||||
Vertex_array _vertices;
|
||||
|
||||
enum { VERTICES_PER_FACE = 4 };
|
||||
|
||||
typedef unsigned Face[VERTICES_PER_FACE];
|
||||
|
||||
Face _faces[NUM_FACES] { { 0, 1, 3, 2 },
|
||||
{ 6, 7, 5, 4 },
|
||||
{ 1, 0, 4, 5 },
|
||||
{ 3, 1, 5, 7 },
|
||||
{ 2, 3, 7, 6 },
|
||||
{ 0, 2, 6, 4 } };
|
||||
|
||||
public:
|
||||
|
||||
Cube_shape(int size)
|
||||
{
|
||||
for (unsigned i = 0; i < NUM_VERTICES; i++)
|
||||
_vertices[i] = Nano3d::Vertex((i&1) ? size : -size,
|
||||
(i&2) ? size : -size,
|
||||
(i&4) ? size : -size);
|
||||
}
|
||||
|
||||
Vertex_array const &vertex_array() const { return _vertices; }
|
||||
|
||||
/**
|
||||
* Call functor 'fn' for each face of the object
|
||||
*
|
||||
* The functor is called with an array of 'unsigned' vertex indices
|
||||
* and the number of indices as arguments.
|
||||
*/
|
||||
template <typename FN>
|
||||
void for_each_face(FN const &fn) const
|
||||
{
|
||||
for (unsigned i = 0; i < NUM_FACES; i++)
|
||||
fn(_faces[i], VERTICES_PER_FACE);
|
||||
}
|
||||
};
|
||||
|
||||
#endif /* _INCLUDE__NANO3D__CUBE_SHAPE_H_ */
|
231
repos/gems/include/nano3d/dodecahedron_shape.h
Normal file
231
repos/gems/include/nano3d/dodecahedron_shape.h
Normal file
@ -0,0 +1,231 @@
|
||||
/*
|
||||
* \brief Dodecahedron 3D object
|
||||
* \author Norman Feske
|
||||
* \date 2015-06-19
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2015 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 _INCLUDE__NANO3D__DODECAHEDRON_SHAPE_H_
|
||||
#define _INCLUDE__NANO3D__DODECAHEDRON_SHAPE_H_
|
||||
|
||||
#include <nano3d/vertex_array.h>
|
||||
|
||||
namespace Nano3d { class Dodecahedron_shape; }
|
||||
|
||||
|
||||
class Nano3d::Dodecahedron_shape
|
||||
{
|
||||
private:
|
||||
|
||||
enum { NUM_VERTICES = 20, NUM_EDGES = 30, NUM_FACES = 12 };
|
||||
|
||||
struct Edge
|
||||
{
|
||||
unsigned left_face, right_face;
|
||||
|
||||
unsigned vertex[2];
|
||||
|
||||
Edge() : left_face(0), right_face(0), vertex { 0, 0 } { }
|
||||
|
||||
Edge(unsigned vertex_0, unsigned vertex_1,
|
||||
unsigned left_face, unsigned right_face)
|
||||
:
|
||||
left_face(left_face), right_face(right_face),
|
||||
vertex { vertex_0, vertex_1 }
|
||||
{ }
|
||||
};
|
||||
|
||||
class Face
|
||||
{
|
||||
public:
|
||||
|
||||
enum { NUM_EDGES = 5 };
|
||||
|
||||
private:
|
||||
|
||||
int _edges[NUM_EDGES];
|
||||
|
||||
public:
|
||||
|
||||
Face() : _edges{} { }
|
||||
|
||||
template <typename... EDGE_INDICES>
|
||||
Face(EDGE_INDICES... edge_indices)
|
||||
:
|
||||
_edges { edge_indices... }
|
||||
{ }
|
||||
|
||||
static constexpr unsigned num_edges() { return NUM_EDGES; }
|
||||
|
||||
int edge(unsigned i) const { return _edges[i]; }
|
||||
};
|
||||
|
||||
typedef Nano3d::Vertex_array<NUM_VERTICES> Vertex_array;
|
||||
|
||||
Vertex_array _vertices;
|
||||
|
||||
Edge _edges[NUM_EDGES];
|
||||
Face _faces[NUM_FACES];
|
||||
|
||||
/* ratio of edge length to radius, as 16.16 fixpoint number */
|
||||
enum { A_TO_R = 46769 };
|
||||
|
||||
/* angle between two edges, scaled to 0..1024 range */
|
||||
enum { DIHEDRAL_ANGLE = 332 };
|
||||
|
||||
public:
|
||||
|
||||
/**
|
||||
* \param r radius of the surrounding sphere
|
||||
*/
|
||||
Dodecahedron_shape(int r)
|
||||
{
|
||||
/*
|
||||
* Vertices
|
||||
*/
|
||||
|
||||
/*
|
||||
* There are four level, each with 5 vertices.
|
||||
*
|
||||
* y0 and y1 are the y positions of the first and second level.
|
||||
* r0 and r1 are the radius of first and second levels.
|
||||
* The third and fourth levels are symetric to the first levels.
|
||||
*/
|
||||
int const y0 = -(r * 52078) >> 16; /* r*0.7947 */
|
||||
int const y1 = -(r * 11030) >> 16;
|
||||
int const r0 = (r * 39780) >> 16; /* r*0.607 */
|
||||
int const r1 = (r * 63910) >> 16;
|
||||
|
||||
enum { ANGLE_STEP = 1024 / 5 };
|
||||
enum { ANGLE_HALF_STEP = 1024 / 10 };
|
||||
|
||||
int j = 0; /* index into '_vertices' array */
|
||||
|
||||
/* level 1 */
|
||||
for (int i = 0; i < 5; i++) {
|
||||
int const a = i*ANGLE_STEP;
|
||||
_vertices[j++] = Vertex((r0*sin_frac16(a)) >> 16, y0,
|
||||
(r0*cos_frac16(a)) >> 16);
|
||||
}
|
||||
|
||||
/* level 2 */
|
||||
for (int i = 0; i < 5; i++) {
|
||||
int const a = i*ANGLE_STEP;
|
||||
_vertices[j++] = Vertex((r1*sin_frac16(a)) >> 16, y1,
|
||||
(r1*cos_frac16(a)) >> 16);
|
||||
}
|
||||
|
||||
/* level 3 */
|
||||
for (int i = 0; i < 5; i++) {
|
||||
int const a = i*ANGLE_STEP + ANGLE_HALF_STEP;
|
||||
_vertices[j++] = Vertex((r1*sin_frac16(a)) >> 16, -y1,
|
||||
(r1*cos_frac16(a)) >> 16);
|
||||
}
|
||||
|
||||
/* level 4 */
|
||||
for (int i = 0; i < 5; i++) {
|
||||
int const a = i*ANGLE_STEP + ANGLE_HALF_STEP;
|
||||
_vertices[j++] = Vertex((r0*sin_frac16(a)) >> 16, -y0,
|
||||
(r0*cos_frac16(a)) >> 16);
|
||||
}
|
||||
|
||||
/*
|
||||
* Edges
|
||||
*/
|
||||
|
||||
j = 0; /* index into '_edges' array */
|
||||
|
||||
/* level 1 */
|
||||
for (int i = 0; i < 5; i++)
|
||||
_edges[j++] = Edge(i, (i+1)%5, i + 1, 0);
|
||||
|
||||
/* level 1 to level 2 */
|
||||
for (int i = 0; i < 5; i++)
|
||||
_edges[j++] = Edge(i, i + 5, 1 + (i + 4)%5, 1 + i);
|
||||
|
||||
/* level 2 to level 3 */
|
||||
for (int i = 0; i < 5; i++)
|
||||
_edges[j++] = Edge(i+5, i + 10, 1 + 5 + (i + 4)%5, 1 + i);
|
||||
|
||||
/* level 3 to level 2 */
|
||||
for (int i = 0; i < 5; i++)
|
||||
_edges[j++] = Edge(i + 10, (i + 1)%5 + 5, 1 + 5 + i, 1 + i);
|
||||
|
||||
/* level 3 to level 4 */
|
||||
for (int i = 0; i < 5; i++)
|
||||
_edges[j++] = Edge(i + 10, i + 15, 1 + 5 + (i + 4)%5, 1 + 5 + i);
|
||||
|
||||
/* level 4 */
|
||||
for (int i = 0; i < 5; i++)
|
||||
_edges[j++] = Edge(i + 15, (i + 1)%5 + 15, 11, 1 + 5 + i);
|
||||
|
||||
/*
|
||||
* Faces
|
||||
*/
|
||||
|
||||
j = 0; /* index into '_faces' array */
|
||||
_faces[j++] = Face(0, 1, 2, 3, 4);
|
||||
|
||||
for (int i = 0; i < 5; i++)
|
||||
_faces[j++] = Face(i, i + 5, i + 10, i + 15, 5 + (1 + i)%5);
|
||||
|
||||
for (int i = 0; i < 5; i++)
|
||||
_faces[j++] = Face(i+20, i + 25, (i + 1)%5 + 20, 10 + (i + 1)%5, 15 + i);
|
||||
|
||||
_faces[j++] = Face(29, 28, 27, 26, 25);
|
||||
}
|
||||
|
||||
Vertex_array const &vertex_array() const { return _vertices; }
|
||||
|
||||
/**
|
||||
* Call functor 'fn' for each face of the object
|
||||
*
|
||||
* The functor is called with an array of 'unsigned' vertex indices
|
||||
* and the number of indices as arguments.
|
||||
*/
|
||||
template <typename FN>
|
||||
void for_each_face(FN const &fn) const
|
||||
{
|
||||
for (unsigned i = 0; i < NUM_FACES; i++) {
|
||||
|
||||
Face const face = _faces[i];
|
||||
|
||||
/*
|
||||
* Asssemble array of vertex indices for the current face.
|
||||
*/
|
||||
unsigned vertex_indices[Face::num_edges()];
|
||||
|
||||
bool skip_face = false;
|
||||
|
||||
for (unsigned j = 0; j < Face::num_edges(); j++) {
|
||||
|
||||
Edge const edge = _edges[face.edge(j)];
|
||||
|
||||
int vertex_idx = -1;
|
||||
|
||||
if (edge.left_face == i)
|
||||
vertex_idx = edge.vertex[1];
|
||||
|
||||
if (edge.right_face == i)
|
||||
vertex_idx = edge.vertex[0];
|
||||
|
||||
if (vertex_idx == -1)
|
||||
skip_face = true;
|
||||
|
||||
vertex_indices[j] = vertex_idx;
|
||||
}
|
||||
|
||||
/* call functor with the information about the face vertices */
|
||||
if (!skip_face)
|
||||
fn(vertex_indices, Face::num_edges());
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
#endif /* _INCLUDE__NANO3D__DODECAHEDRON_SHAPE_H_ */
|
313
repos/gems/include/nano3d/scene.h
Normal file
313
repos/gems/include/nano3d/scene.h
Normal file
@ -0,0 +1,313 @@
|
||||
/*
|
||||
* \brief Simple framework for rendering an animated scene
|
||||
* \author Norman Feske
|
||||
* \date 2015-06-22
|
||||
*
|
||||
* The 'Scene' class template contains the code for setting up a nitpicker
|
||||
* view with a triple-buffer for rendering tearing-free animations.
|
||||
* A derrived class implements the to-be-displayed content in the virtual
|
||||
* 'render' method.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2015 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 _INCLUDE__NANO3D__SCENE_H_
|
||||
#define _INCLUDE__NANO3D__SCENE_H_
|
||||
|
||||
/* Genode includes */
|
||||
#include <timer_session/connection.h>
|
||||
#include <nitpicker_session/connection.h>
|
||||
#include <os/surface.h>
|
||||
#include <os/pixel_alpha8.h>
|
||||
#include <os/attached_dataspace.h>
|
||||
#include <input/event.h>
|
||||
|
||||
namespace Nano3d {
|
||||
|
||||
struct Input_handler;
|
||||
template <typename> class Scene;
|
||||
}
|
||||
|
||||
|
||||
struct Nano3d::Input_handler
|
||||
{
|
||||
virtual void handle_input(Input::Event const [], unsigned num_events) = 0;
|
||||
};
|
||||
|
||||
|
||||
template <typename PT>
|
||||
class Nano3d::Scene
|
||||
{
|
||||
public:
|
||||
|
||||
class Unsupported_color_depth { };
|
||||
|
||||
typedef Genode::Pixel_alpha8 Pixel_alpha8;
|
||||
|
||||
virtual void render(Genode::Surface<PT> &pixel_surface,
|
||||
Genode::Surface<Pixel_alpha8> &alpha_surface) = 0;
|
||||
|
||||
private:
|
||||
|
||||
Genode::Signal_receiver &_sig_rec;
|
||||
|
||||
/**
|
||||
* Position and size of nitpicker view
|
||||
*/
|
||||
Nitpicker::Point const _pos;
|
||||
Nitpicker::Area const _size;
|
||||
|
||||
Nitpicker::Connection _nitpicker;
|
||||
|
||||
struct Mapped_framebuffer
|
||||
{
|
||||
enum { NUM_BUFFERS = 3 };
|
||||
|
||||
static Framebuffer::Session &
|
||||
_init_framebuffer(Nitpicker::Connection &nitpicker,
|
||||
Nitpicker::Area const size)
|
||||
{
|
||||
Framebuffer::Mode::Format const format = nitpicker.mode().format();
|
||||
if (format != Framebuffer::Mode::RGB565) {
|
||||
PERR("framebuffer mode %d is not supported\n", format);
|
||||
throw Unsupported_color_depth();
|
||||
}
|
||||
|
||||
/*
|
||||
* Dimension the virtual framebuffer 3 times as high as the
|
||||
* visible view because it contains the visible buffer, the
|
||||
* front buffer, and the back buffer.
|
||||
*/
|
||||
bool const use_alpha = true;
|
||||
unsigned const height = size.h()*NUM_BUFFERS;
|
||||
nitpicker.buffer(Framebuffer::Mode(size.w(), height, format),
|
||||
use_alpha);
|
||||
|
||||
return *nitpicker.framebuffer();
|
||||
}
|
||||
|
||||
Framebuffer::Session &framebuffer;
|
||||
|
||||
Framebuffer::Mode const mode = framebuffer.mode();
|
||||
|
||||
/**
|
||||
* Return visible size
|
||||
*/
|
||||
Nitpicker::Area size() const
|
||||
{
|
||||
return Nitpicker::Area(mode.width(), mode.height()/NUM_BUFFERS);
|
||||
}
|
||||
|
||||
Genode::Attached_dataspace ds { framebuffer.dataspace() };
|
||||
|
||||
PT *pixel_base(unsigned i)
|
||||
{
|
||||
return (PT *)(ds.local_addr<PT>() + i*size().count());
|
||||
}
|
||||
|
||||
Pixel_alpha8 *alpha_base(unsigned i)
|
||||
{
|
||||
Pixel_alpha8 * const alpha_base =
|
||||
(Pixel_alpha8 *)(ds.local_addr<PT>() + NUM_BUFFERS*size().count());
|
||||
|
||||
return alpha_base + i*size().count();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set or clear the input mask for the virtual framebuffer
|
||||
*/
|
||||
void input_mask(bool input_enabled)
|
||||
{
|
||||
/*
|
||||
* The input-mask buffer follows the alpha buffer. Hence, we
|
||||
* can obtain the base address by requesting the base of
|
||||
* the (non-exiting) alpha buffer (using NUM_BUFFERS as index)
|
||||
* beyond the actual alpha buffers.
|
||||
*/
|
||||
Genode::memset(alpha_base(NUM_BUFFERS), input_enabled,
|
||||
NUM_BUFFERS*size().count());
|
||||
}
|
||||
|
||||
Mapped_framebuffer(Nitpicker::Connection &nitpicker, Nitpicker::Area size)
|
||||
:
|
||||
framebuffer(_init_framebuffer(nitpicker, size))
|
||||
{ }
|
||||
|
||||
} _framebuffer { _nitpicker, _size };
|
||||
|
||||
Nitpicker::Session::View_handle _view_handle = _nitpicker.create_view();
|
||||
|
||||
typedef Genode::Surface<PT> Pixel_surface;
|
||||
typedef Genode::Surface<Genode::Pixel_alpha8> Alpha_surface;
|
||||
|
||||
struct Surface
|
||||
{
|
||||
Pixel_surface pixel;
|
||||
Alpha_surface alpha;
|
||||
|
||||
Surface(PT *pixel_base, Genode::Pixel_alpha8 *alpha_base,
|
||||
Genode::Surface_base::Area size)
|
||||
:
|
||||
pixel(pixel_base, size), alpha(alpha_base, size)
|
||||
{ }
|
||||
|
||||
Genode::Surface_base::Area size() const { return pixel.size(); }
|
||||
|
||||
template <typename T>
|
||||
void _clear(Genode::Surface<T> &surface)
|
||||
{
|
||||
Genode::size_t n = (surface.size().count()*sizeof(T))/sizeof(long);
|
||||
for (long *dst = (long *)surface.addr(); n--; dst++)
|
||||
*dst = 0;
|
||||
}
|
||||
|
||||
void clear()
|
||||
{
|
||||
_clear(pixel);
|
||||
_clear(alpha);
|
||||
}
|
||||
};
|
||||
|
||||
Surface _surface_0 { _framebuffer.pixel_base(0), _framebuffer.alpha_base(0),
|
||||
_framebuffer.size() };
|
||||
Surface _surface_1 { _framebuffer.pixel_base(1), _framebuffer.alpha_base(1),
|
||||
_framebuffer.size() };
|
||||
Surface _surface_2 { _framebuffer.pixel_base(2), _framebuffer.alpha_base(2),
|
||||
_framebuffer.size() };
|
||||
|
||||
Surface *_surface_visible = &_surface_0;
|
||||
Surface *_surface_front = &_surface_1;
|
||||
Surface *_surface_back = &_surface_2;
|
||||
|
||||
bool _do_sync = false;
|
||||
|
||||
Timer::Connection _timer;
|
||||
|
||||
Genode::Attached_dataspace _input_ds { _nitpicker.input()->dataspace() };
|
||||
|
||||
Input_handler *_input_handler = nullptr;
|
||||
|
||||
void _handle_input(unsigned)
|
||||
{
|
||||
if (!_input_handler)
|
||||
return;
|
||||
|
||||
while (int num = _nitpicker.input()->flush()) {
|
||||
|
||||
auto const *ev_buf = _input_ds.local_addr<Input::Event>();
|
||||
|
||||
if (_input_handler)
|
||||
_input_handler->handle_input(ev_buf, num);
|
||||
}
|
||||
}
|
||||
|
||||
Genode::Signal_dispatcher<Scene> _input_dispatcher {
|
||||
_sig_rec, *this, &Scene::_handle_input };
|
||||
|
||||
void _swap_back_and_front_surfaces()
|
||||
{
|
||||
Surface *tmp = _surface_back;
|
||||
_surface_back = _surface_front;
|
||||
_surface_front = tmp;
|
||||
}
|
||||
|
||||
void _swap_visible_and_front_surfaces()
|
||||
{
|
||||
Surface *tmp = _surface_visible;
|
||||
_surface_visible = _surface_front;
|
||||
_surface_front = tmp;
|
||||
}
|
||||
|
||||
void _handle_period(unsigned)
|
||||
{
|
||||
if (_do_sync)
|
||||
return;
|
||||
|
||||
_surface_back->clear();
|
||||
|
||||
render(_surface_back->pixel, _surface_back->alpha);
|
||||
|
||||
_swap_back_and_front_surfaces();
|
||||
|
||||
/* swap front and back buffers on next sync */
|
||||
_do_sync = true;
|
||||
}
|
||||
|
||||
Genode::Signal_dispatcher<Scene> _periodic_dispatcher {
|
||||
_sig_rec, *this, &Scene::_handle_period };
|
||||
|
||||
void _handle_sync(unsigned)
|
||||
{
|
||||
/* rendering of scene is not complete, yet */
|
||||
if (!_do_sync)
|
||||
return;
|
||||
|
||||
_swap_visible_and_front_surfaces();
|
||||
_swap_back_and_front_surfaces();
|
||||
|
||||
int const h = _framebuffer.size().h();
|
||||
|
||||
int const buf_y = (_surface_visible == &_surface_0) ? 0
|
||||
: (_surface_visible == &_surface_1) ? -h
|
||||
: -2*h;
|
||||
|
||||
Nitpicker::Point const offset(0, buf_y);
|
||||
_nitpicker.enqueue<Command::Offset>(_view_handle, offset);
|
||||
_nitpicker.execute();
|
||||
|
||||
_do_sync = false;
|
||||
}
|
||||
|
||||
Genode::Signal_dispatcher<Scene> _sync_dispatcher {
|
||||
_sig_rec, *this, &Scene::_handle_sync };
|
||||
|
||||
typedef Nitpicker::Session::Command Command;
|
||||
|
||||
public:
|
||||
|
||||
Scene(Genode::Signal_receiver &sig_rec, unsigned update_rate_ms,
|
||||
Nitpicker::Point pos, Nitpicker::Area size)
|
||||
:
|
||||
_sig_rec(sig_rec), _pos(pos), _size(size)
|
||||
{
|
||||
Nitpicker::Rect rect(_pos, _size);
|
||||
_nitpicker.enqueue<Command::Geometry>(_view_handle, rect);
|
||||
_nitpicker.enqueue<Command::To_front>(_view_handle);
|
||||
_nitpicker.execute();
|
||||
|
||||
_nitpicker.input()->sigh(_input_dispatcher);
|
||||
|
||||
_timer.sigh(_periodic_dispatcher);
|
||||
_timer.trigger_periodic(1000*update_rate_ms);
|
||||
|
||||
_framebuffer.framebuffer.sync_sigh(_sync_dispatcher);
|
||||
}
|
||||
|
||||
static void dispatch_signals_loop(Genode::Signal_receiver &sig_rec)
|
||||
{
|
||||
while (1) {
|
||||
|
||||
Genode::Signal signal = sig_rec.wait_for_signal();
|
||||
|
||||
Genode::Signal_dispatcher_base *dispatcher =
|
||||
static_cast<Genode::Signal_dispatcher_base *>(signal.context());
|
||||
|
||||
dispatcher->dispatch(signal.num());
|
||||
}
|
||||
}
|
||||
|
||||
unsigned long elapsed_ms() const { return _timer.elapsed_ms(); }
|
||||
|
||||
void input_handler(Input_handler *input_handler)
|
||||
{
|
||||
_framebuffer.input_mask(input_handler ? true : false);
|
||||
_input_handler = input_handler;
|
||||
}
|
||||
};
|
||||
|
||||
#endif /* _INCLUDE__NANO3D__SCENE_H_ */
|
120
repos/gems/include/nano3d/sincos_frac16.h
Normal file
120
repos/gems/include/nano3d/sincos_frac16.h
Normal file
@ -0,0 +1,120 @@
|
||||
/*
|
||||
* \brief Table of sine and cosine values in 16.16 fractional format
|
||||
* \author Norman Feske
|
||||
* \date 2015-06-19
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2015 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 _INCLUDE__NANO3D__SINCOS_FRAC16_H_
|
||||
#define _INCLUDE__NANO3D__SINCOS_FRAC16_H_
|
||||
|
||||
namespace Nano3d { class Sincos_frac16; };
|
||||
|
||||
|
||||
class Nano3d::Sincos_frac16
|
||||
{
|
||||
public:
|
||||
|
||||
enum { STEPS = 1024 };
|
||||
|
||||
private:
|
||||
|
||||
int _table[STEPS + STEPS/4];
|
||||
|
||||
public:
|
||||
|
||||
inline Sincos_frac16();
|
||||
|
||||
int sin(int angle) const { return _table[angle & (STEPS - 1)]; }
|
||||
int cos(int angle) const { return sin(angle + STEPS/4); }
|
||||
};
|
||||
|
||||
|
||||
Nano3d::Sincos_frac16::Sincos_frac16()
|
||||
{
|
||||
int const cos_mid = 0x7fff;
|
||||
int const cos_low = 0x310b; /* cos(360/1024) = 0x7fff6216 */
|
||||
int const sin_mid = 0x00c9;
|
||||
int const sin_low = 0x07c4; /* sin(360/1024) = 0x00c90f87 */
|
||||
|
||||
int x_mid = 0x7fff;
|
||||
int x_low = 0x7fff; /* x = 1.0 */
|
||||
int y_mid = 0;
|
||||
int y_low = 0; /* y = 0.0 */
|
||||
|
||||
int nx_high, ny_high;
|
||||
int nx_mid, nx_low;
|
||||
int ny_mid, ny_low;
|
||||
|
||||
for (unsigned i = 0; i < (STEPS >> 2); i++) {
|
||||
|
||||
/* store current sine value */
|
||||
_table[i] = y_mid << 1;
|
||||
_table[(STEPS >> 1) - i - 1] = y_mid << 1;
|
||||
_table[i + (STEPS >> 1)] = -y_mid << 1;
|
||||
_table[STEPS - i - 1] = -y_mid << 1;
|
||||
|
||||
/* rotate sin/cos values */
|
||||
|
||||
/* x' = x*cos - y*sin */
|
||||
|
||||
nx_low = x_low*cos_low
|
||||
- y_low*sin_low;
|
||||
|
||||
nx_mid = x_low*cos_mid + x_mid*cos_low
|
||||
- y_low*sin_mid - y_mid*sin_low;
|
||||
nx_mid += (nx_low >> 14);
|
||||
|
||||
nx_high = x_mid*cos_mid
|
||||
- y_mid*sin_mid
|
||||
+ (nx_mid >> 15);
|
||||
|
||||
nx_high = nx_high << 1;
|
||||
|
||||
/* y' = y*cos + x*sin */
|
||||
|
||||
ny_low = y_low*cos_low
|
||||
+ x_low*sin_low;
|
||||
|
||||
ny_mid = y_low*cos_mid + y_mid*cos_low
|
||||
+ x_low*sin_mid + x_mid*sin_low
|
||||
+ (ny_low >> 14);
|
||||
|
||||
ny_high = y_mid*cos_mid
|
||||
+ x_mid*sin_mid
|
||||
+ (ny_mid >> 15);
|
||||
|
||||
ny_high = ny_high << 1;
|
||||
|
||||
/* use new sin/cos values for next iteration, preserve sign */
|
||||
x_low = (nx_high & 0x80000000) ? (nx_high | (~0 << 16)) : (nx_high & 0xffff);
|
||||
x_low = x_low >> 1;
|
||||
x_mid = nx_high >> 16;
|
||||
|
||||
y_low = (ny_high & 0x80000000) ? (ny_high | (~0 << 16)) : (ny_high & 0xffff);
|
||||
y_low = y_low >> 1;
|
||||
y_mid = ny_high >> 16;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
namespace Nano3d {
|
||||
|
||||
static Sincos_frac16 const &sincos_frac16()
|
||||
{
|
||||
static Sincos_frac16 inst;
|
||||
return inst;
|
||||
}
|
||||
|
||||
|
||||
static inline int sin_frac16(int angle) { return sincos_frac16().sin(angle); }
|
||||
static inline int cos_frac16(int angle) { return sincos_frac16().cos(angle); }
|
||||
};
|
||||
|
||||
#endif /* _INCLUDE__NANO3D__SINCOS_FRAC16_H_ */
|
41
repos/gems/include/nano3d/sqrt.h
Normal file
41
repos/gems/include/nano3d/sqrt.h
Normal file
@ -0,0 +1,41 @@
|
||||
/*
|
||||
* \brief Square root of integer values
|
||||
* \date 2010-09-27
|
||||
* \author Norman Feske
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2010-2015 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 _INCLUDE__NANO3D__SQRT_H_
|
||||
#define _INCLUDE__NANO3D__SQRT_H__
|
||||
|
||||
namespace Nano3d {
|
||||
|
||||
/**
|
||||
* Calculate square root of an integer value
|
||||
*/
|
||||
template <typename T>
|
||||
T sqrt(T value)
|
||||
{
|
||||
/*
|
||||
* Calculate square root using nested intervalls. The range of values
|
||||
* is log(x) with x being the maximum value of type T. We narrow the
|
||||
* result bit by bit starting with the most significant bit.
|
||||
*/
|
||||
T result = 0;
|
||||
for (T i = sizeof(T)*8 / 2; i > 0; i--) {
|
||||
T const bit = i - 1;
|
||||
T const test = result + (1 << bit);
|
||||
if (test*test <= value)
|
||||
result = test;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* _INCLUDE__NANO3D__SQRT_H__ */
|
161
repos/gems/include/nano3d/vertex_array.h
Normal file
161
repos/gems/include/nano3d/vertex_array.h
Normal file
@ -0,0 +1,161 @@
|
||||
/*
|
||||
* \brief Vertex array
|
||||
* \author Norman Feske
|
||||
* \date 2010-09-27
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2010-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.
|
||||
*/
|
||||
|
||||
#ifndef _INCLUDE__NANO3D__VERTEX_ARRAY_H_
|
||||
#define _INCLUDE__NANO3D__VERTEX_ARRAY_H_
|
||||
|
||||
#include <nano3d/sincos_frac16.h>
|
||||
|
||||
namespace Nano3d {
|
||||
|
||||
template <typename> class Vec2;
|
||||
template <typename> class Vec3;
|
||||
|
||||
typedef Vec3<int> Vertex;
|
||||
|
||||
template <unsigned> class Vertex_array;
|
||||
}
|
||||
|
||||
|
||||
template <typename T>
|
||||
class Nano3d::Vec2
|
||||
{
|
||||
private:
|
||||
|
||||
T _x, _y;
|
||||
|
||||
public:
|
||||
|
||||
Vec2() : _x(0), _y(0) { }
|
||||
|
||||
Vec2(T x, T y) : _x(x), _y(y) { }
|
||||
|
||||
T &x() { return _x; }
|
||||
T &y() { return _y; }
|
||||
|
||||
T x() const { return _x; }
|
||||
T y() const { return _y; }
|
||||
|
||||
void rotate(int sina, int cosa)
|
||||
{
|
||||
int x = _x*cosa - _y*sina;
|
||||
int y = _x*sina + _y*cosa;
|
||||
|
||||
_x = x >> 16;
|
||||
_y = y >> 16;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
template <typename T>
|
||||
class Nano3d::Vec3
|
||||
{
|
||||
private:
|
||||
|
||||
T _x, _y, _z;
|
||||
|
||||
public:
|
||||
|
||||
Vec3() : _x(0), _y(0), _z(0) { }
|
||||
|
||||
Vec3(T x, T y, T z) : _x(x), _y(y), _z(z) { }
|
||||
|
||||
T &x() { return _x; }
|
||||
T &y() { return _y; }
|
||||
T &z() { return _z; }
|
||||
|
||||
T x() const { return _x; }
|
||||
T y() const { return _y; }
|
||||
T z() const { return _z; }
|
||||
};
|
||||
|
||||
|
||||
template <unsigned MAX_VERTICES>
|
||||
class Nano3d::Vertex_array
|
||||
{
|
||||
protected:
|
||||
|
||||
Vertex _buf[MAX_VERTICES];
|
||||
|
||||
void _rotate(int & (Vec3<int>::*x)(), int & (Vec3<int>::*y)(), int angle)
|
||||
{
|
||||
int sina = sin_frac16(angle);
|
||||
int cosa = cos_frac16(angle);
|
||||
|
||||
Vertex *vertex = &_buf[0];
|
||||
|
||||
for (unsigned i = 0; i < MAX_VERTICES; i++, vertex++) {
|
||||
|
||||
Vec2<int> p((vertex->*x)(), (vertex->*y)());
|
||||
|
||||
p.rotate(sina, cosa);
|
||||
|
||||
(vertex->*x)() = p.x();
|
||||
(vertex->*y)() = p.y();
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
Vertex_array() { }
|
||||
|
||||
Vertex &operator [] (unsigned index) { return _buf[index]; }
|
||||
|
||||
/**
|
||||
* Rotate vertices around x, y, and z axis
|
||||
*/
|
||||
void rotate_x(int angle) { _rotate(&Vertex::y, &Vertex::z, angle); }
|
||||
void rotate_y(int angle) { _rotate(&Vertex::x, &Vertex::z, angle); }
|
||||
void rotate_z(int angle) { _rotate(&Vertex::x, &Vertex::y, angle); }
|
||||
|
||||
/**
|
||||
* Apply central projection to vertices
|
||||
*
|
||||
* FIXME: Add proper documentation of the parameters.
|
||||
*
|
||||
* \param z_shift Recommended value is 1600
|
||||
* \param distance Recommended value is screen height
|
||||
*/
|
||||
void project(int z_shift, int distance)
|
||||
{
|
||||
Vertex *vertex = &_buf[0];
|
||||
for (unsigned i = 0; i < MAX_VERTICES; i++, vertex++) {
|
||||
|
||||
int z = (vertex->z() >> 5) + z_shift - 1;
|
||||
|
||||
/* avoid division by zero */
|
||||
if (z == 0) z += 1;
|
||||
|
||||
vertex->x() = ((vertex->x() >> 5) * distance) / z;
|
||||
vertex->y() = ((vertex->y() >> 5) * distance) / z;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Translate vertices
|
||||
*/
|
||||
void translate(int dx, int dy, int dz)
|
||||
{
|
||||
Vertex *vertex = &_buf[0];
|
||||
for (unsigned i = 0; i < MAX_VERTICES; i++, vertex++) {
|
||||
vertex->x() += dx;
|
||||
vertex->y() += dy;
|
||||
vertex->z() += dz;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
#endif /* _INCLUDE__NANO3D__VERTEX_ARRAY_H_ */
|
216
repos/gems/include/polygon_gfx/clipping.h
Normal file
216
repos/gems/include/polygon_gfx/clipping.h
Normal file
@ -0,0 +1,216 @@
|
||||
/*
|
||||
* \brief Polygon clipping
|
||||
* \date 2015-06-19
|
||||
* \author Norman Feske
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2015 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 _INCLUDE__POLYGON_GFX__CLIPPING_H_
|
||||
#define _INCLUDE__POLYGON_GFX__CLIPPING_H_
|
||||
|
||||
namespace Polygon {
|
||||
|
||||
struct Point_base;
|
||||
|
||||
inline int intersect_ratio(int, int, int);
|
||||
|
||||
template <typename> struct Clipper_vertical;
|
||||
template <typename> struct Clipper_horizontal;
|
||||
|
||||
struct Clipper_min;
|
||||
struct Clipper_max;
|
||||
|
||||
template <typename, typename, typename> struct Clipper;
|
||||
|
||||
template <typename> struct Clipper_2d;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Common base class of polygon points
|
||||
*/
|
||||
struct Polygon::Point_base : Genode::Point<>
|
||||
{
|
||||
/*
|
||||
* Number of attributes to interpolate along the polygon edges. This value
|
||||
* must be defined by each derived class.
|
||||
*/
|
||||
enum { NUM_EDGE_ATTRIBUTES = 1 };
|
||||
|
||||
/**
|
||||
* Constructors
|
||||
*/
|
||||
Point_base() { }
|
||||
Point_base(int x, int y): Genode::Point<>(x, y) { }
|
||||
|
||||
/**
|
||||
* Return edge attribute by ID
|
||||
*/
|
||||
inline int edge_attr(int id) const { return x(); }
|
||||
|
||||
/**
|
||||
* Assign value to edge attribute with specified ID
|
||||
*/
|
||||
inline void edge_attr(int id, int value) { *this = Point_base(value, y()); }
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Calculate ratio of range intersection
|
||||
*
|
||||
* \param v_start Start of range
|
||||
* \param v_end End of range
|
||||
* \param v_cut Range cut (should be in interval v_start...v_end)
|
||||
* \return Ratio of intersection as 16.16 fixpoint
|
||||
*
|
||||
* The input arguments 'v_start', 'v_end', 'v_cut' must use only
|
||||
* the lower 16 bits of the int type.
|
||||
*/
|
||||
inline int Polygon::intersect_ratio(int v_start, int v_end, int v_cut)
|
||||
{
|
||||
int dv = v_end - v_start,
|
||||
dv_cut = v_cut - v_start;
|
||||
|
||||
return dv ? (dv_cut<<16)/dv : 0;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Support for vertical clipping boundary
|
||||
*/
|
||||
template <typename POINT>
|
||||
struct Polygon::Clipper_vertical
|
||||
{
|
||||
/**
|
||||
* Select clipping-sensitive attribute from polygon point
|
||||
*/
|
||||
static int clip_value(POINT p) { return p.x(); }
|
||||
|
||||
/**
|
||||
* Calculate intersection point
|
||||
*/
|
||||
static POINT clip(POINT p1, POINT p2, int clip)
|
||||
{
|
||||
/*
|
||||
* Enforce unique x order of points to apply rounding errors
|
||||
* consistently also when edge points are specified in reverse.
|
||||
* Typically the same edge is used in reverse direction by
|
||||
* each neighboured polygon.
|
||||
*/
|
||||
if (clip_value(p1) > clip_value(p2)) { POINT tmp = p1; p1 = p2; p2 = tmp; }
|
||||
|
||||
/* calculate ratio of the intersection of edge and clipping boundary */
|
||||
int ratio = intersect_ratio(p1.x(), p2.x(), clip);
|
||||
|
||||
/* calculate y value at intersection point */
|
||||
POINT result;
|
||||
*(Point_base *)&result = Point_base(clip, p1.y() + ((ratio*(p2.y() - p1.y()))>>16));
|
||||
|
||||
/* calculate intersection values for edge attributes other than x */
|
||||
for (int i = 1; i < POINT::NUM_EDGE_ATTRIBUTES; i++) {
|
||||
int v1 = p1.edge_attr(i),
|
||||
v2 = p2.edge_attr(i);
|
||||
result.edge_attr(i, v1 + ((ratio*(v2 - v1))>>16));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Support for horizontal clipping boundary
|
||||
*/
|
||||
template <typename POINT>
|
||||
struct Polygon::Clipper_horizontal
|
||||
{
|
||||
/**
|
||||
* Select clipping-sensitive attribute from polygon point
|
||||
*/
|
||||
static int clip_value(POINT p) { return p.y(); }
|
||||
|
||||
/**
|
||||
* Calculate intersection point
|
||||
*/
|
||||
static POINT clip(POINT p1, POINT p2, int clip)
|
||||
{
|
||||
if (clip_value(p1) > clip_value(p2)) { POINT tmp = p1; p1 = p2; p2 = tmp; }
|
||||
|
||||
/* calculate ratio of the intersection of edge and clipping boundary */
|
||||
int ratio = intersect_ratio(clip_value(p1), clip_value(p2), clip);
|
||||
|
||||
/* calculate y value at intersection point */
|
||||
POINT result;
|
||||
*(Point_base *)&result = Point_base(p1.x() + ((ratio*(p2.x() - p1.x()))>>16), clip);
|
||||
|
||||
/* calculate intersection values for edge attributes other than x */
|
||||
for (int i = 1; i < POINT::NUM_EDGE_ATTRIBUTES; i++) {
|
||||
int v1 = p1.edge_attr(i),
|
||||
v2 = p2.edge_attr(i);
|
||||
result.edge_attr(i, v1 + ((ratio*(v2 - v1))>>16));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Support for clipping against a lower boundary
|
||||
*/
|
||||
struct Polygon::Clipper_min
|
||||
{
|
||||
static bool inside(int value, int boundary) { return value >= boundary; }
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Support for clipping against a higher boundary
|
||||
*/
|
||||
struct Polygon::Clipper_max
|
||||
{
|
||||
static bool inside(int value, int boundary) { return value <= boundary; }
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* One-dimensional clipping
|
||||
*
|
||||
* This template allows for the aggregation of the policies defined above to
|
||||
* build specialized 1D-clipping functions for upper/lower vertical/horizontal
|
||||
* clipping boundaries and for polygon points with different attributes.
|
||||
*/
|
||||
template <typename CLIPPER_DIRECTION, typename CLIPPER_MINMAX, typename POINT>
|
||||
struct Polygon::Clipper : CLIPPER_DIRECTION, CLIPPER_MINMAX
|
||||
{
|
||||
/**
|
||||
* Check whether point is inside the clipping area or not
|
||||
*/
|
||||
static bool inside(POINT p, int clip)
|
||||
{
|
||||
return CLIPPER_MINMAX::inside(CLIPPER_DIRECTION::clip_value(p), clip);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Create clipping helpers
|
||||
*
|
||||
* This class is used as a compound containing all rules to
|
||||
* clip a polygon against a 2d region such as the clipping
|
||||
* region of a Canvas.
|
||||
*/
|
||||
template <typename POINT>
|
||||
struct Polygon::Clipper_2d
|
||||
{
|
||||
typedef Clipper<Clipper_horizontal<POINT>, Clipper_min, POINT> Top;
|
||||
typedef Clipper<Clipper_horizontal<POINT>, Clipper_max, POINT> Bottom;
|
||||
typedef Clipper<Clipper_vertical<POINT>, Clipper_min, POINT> Left;
|
||||
typedef Clipper<Clipper_vertical<POINT>, Clipper_max, POINT> Right;
|
||||
};
|
||||
|
||||
#endif /* _INCLUDE__POLYGON_GFX__CLIPPING_H_ */
|
76
repos/gems/include/polygon_gfx/interpolate_rgb565.h
Normal file
76
repos/gems/include/polygon_gfx/interpolate_rgb565.h
Normal file
@ -0,0 +1,76 @@
|
||||
/*
|
||||
* \brief RGB565-optimized interpolation functions for polygon painting
|
||||
* \date 2015-06-19
|
||||
* \author Norman Feske
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2015 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 _INCLUDE__POLYGON_GFX__INTERPOLATE_RGB565_H_
|
||||
#define _INCLUDE__POLYGON_GFX__INTERPOLATE_RGB565_H_
|
||||
|
||||
/* Genode includes */
|
||||
#include <util/dither_matrix.h>
|
||||
#include <os/pixel_rgb565.h>
|
||||
#include <polygon_gfx/interpolate_rgba.h>
|
||||
|
||||
namespace Polygon {
|
||||
|
||||
using Genode::Pixel_rgb565;
|
||||
|
||||
template <>
|
||||
inline void interpolate_rgba(Color, Color, Pixel_rgb565 *,
|
||||
unsigned char *, unsigned, int, int);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Specialization that employs dithering
|
||||
*/
|
||||
template <>
|
||||
inline void Polygon::interpolate_rgba(Color start, Color end, Pixel_rgb565 *dst,
|
||||
unsigned char *dst_alpha,
|
||||
unsigned num_values, int x, int y)
|
||||
{
|
||||
/* sanity check */
|
||||
if (num_values <= 0) return;
|
||||
|
||||
/* use 16.16 fixpoint values for the calculation */
|
||||
int r_ascent = ((end.r - start.r)<<16) / (int)num_values,
|
||||
g_ascent = ((end.g - start.g)<<16) / (int)num_values,
|
||||
b_ascent = ((end.b - start.b)<<16) / (int)num_values,
|
||||
a_ascent = ((end.a - start.a)<<16) / (int)num_values;
|
||||
|
||||
/* set start values for color components */
|
||||
int r = start.r<<16,
|
||||
g = start.g<<16,
|
||||
b = start.b<<16,
|
||||
a = start.a<<16;
|
||||
|
||||
for ( ; num_values--; dst++, dst_alpha++, x++) {
|
||||
|
||||
int const dither_value = Genode::Dither_matrix::value(x, y) << 12;
|
||||
|
||||
/* combine current color value with existing pixel via alpha blending */
|
||||
*dst = Pixel_rgb565::mix(*dst,
|
||||
Pixel_rgb565((r + dither_value) >> 16,
|
||||
(g + dither_value) >> 16,
|
||||
(b + dither_value) >> 16),
|
||||
(a + dither_value) >> 16);
|
||||
|
||||
*dst_alpha += ((255 - *dst_alpha)*(a + dither_value)) >> (16 + 8);
|
||||
|
||||
/* increment color-component values by ascent */
|
||||
r += r_ascent;
|
||||
g += g_ascent;
|
||||
b += b_ascent;
|
||||
a += a_ascent;
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* _INCLUDE__POLYGON_GFX__INTERPOLATE_RGB565_H_ */
|
70
repos/gems/include/polygon_gfx/interpolate_rgba.h
Normal file
70
repos/gems/include/polygon_gfx/interpolate_rgba.h
Normal file
@ -0,0 +1,70 @@
|
||||
/*
|
||||
* \brief Interpolation functions for polygon painting
|
||||
* \date 2015-06-19
|
||||
* \author Norman Feske
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2015 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 _INCLUDE__POLYGON_GFX__INTERPOLATE_RGBA_H_
|
||||
#define _INCLUDE__POLYGON_GFX__INTERPOLATE_RGBA_H_
|
||||
|
||||
/* Genode includes */
|
||||
#include <util/color.h>
|
||||
|
||||
namespace Polygon {
|
||||
|
||||
using Genode::Color;
|
||||
|
||||
template <typename PT>
|
||||
static inline void interpolate_rgba(Color, Color, PT *, unsigned char *,
|
||||
unsigned, int, int);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Interpolate color values
|
||||
*/
|
||||
template <typename PT>
|
||||
static inline void Polygon::interpolate_rgba(Polygon::Color start,
|
||||
Polygon::Color end,
|
||||
PT *dst,
|
||||
unsigned char *dst_alpha,
|
||||
unsigned num_values,
|
||||
int x, int y)
|
||||
{
|
||||
/* sanity check */
|
||||
if (num_values == 0) return;
|
||||
|
||||
/* use 16.16 fixpoint values for the calculation */
|
||||
int const r_ascent = ((end.r - start.r)<<16) / (int)num_values,
|
||||
g_ascent = ((end.g - start.g)<<16) / (int)num_values,
|
||||
b_ascent = ((end.b - start.b)<<16) / (int)num_values,
|
||||
a_ascent = ((end.a - start.a)<<16) / (int)num_values;
|
||||
|
||||
/* set start values for color components */
|
||||
int r = start.r<<16,
|
||||
g = start.g<<16,
|
||||
b = start.b<<16,
|
||||
a = start.a<<16;
|
||||
|
||||
for ( ; num_values--; dst++, dst_alpha++) {
|
||||
|
||||
/* combine current color value with existing pixel via alpha blending */
|
||||
*dst = PT::mix(*dst, PT(r>>16, g>>16, b>>16), a>>16);
|
||||
*dst_alpha += ((255 - *dst_alpha)*a) >> (16 + 8);
|
||||
|
||||
/* increment color-component values by ascent */
|
||||
r += r_ascent;
|
||||
g += g_ascent;
|
||||
b += b_ascent;
|
||||
a += a_ascent;
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* _INCLUDE__POLYGON_GFX__INTERPOLATE_RGBA_H_ */
|
259
repos/gems/include/polygon_gfx/polygon_painter_base.h
Normal file
259
repos/gems/include/polygon_gfx/polygon_painter_base.h
Normal file
@ -0,0 +1,259 @@
|
||||
/*
|
||||
* \brief Common base of polygon painters
|
||||
* \author Norman Feske
|
||||
* \date 2015-06-19
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2015 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 _INCLUDE__POLYGON_GFX__POLYGON_PAINTER_BASE_H_
|
||||
#define _INCLUDE__POLYGON_GFX__POLYGON_PAINTER_BASE_H_
|
||||
|
||||
/* Genode includes */
|
||||
#include <base/allocator.h>
|
||||
#include <util/geometry.h>
|
||||
#include <util/misc_math.h>
|
||||
#include <polygon_gfx/clipping.h>
|
||||
|
||||
namespace Polygon { class Painter_base; }
|
||||
|
||||
|
||||
class Polygon::Painter_base
|
||||
{
|
||||
private:
|
||||
|
||||
/**
|
||||
* Interpolate linearly between start value and end value
|
||||
*/
|
||||
static inline void _interpolate(int start, int end, int *dst,
|
||||
unsigned num_values)
|
||||
{
|
||||
/* sanity check */
|
||||
if (num_values == 0) return;
|
||||
|
||||
int const ascent = ((end - start)<<16)/(int)num_values;
|
||||
|
||||
for (int curr = start<<16; num_values--; curr += ascent)
|
||||
*dst++ = curr>>16;
|
||||
}
|
||||
|
||||
/**
|
||||
* Clip polygon against boundary
|
||||
*
|
||||
* \param src Array of unclipped source-polygon points
|
||||
* \param src_num_points Number of source-polygon points
|
||||
* \param dst Destination buffer for clipped polygon points
|
||||
* \param clip Clipping boundary
|
||||
* \return Number of resulting polygon points
|
||||
*/
|
||||
template <typename CLIPPER, typename POINT>
|
||||
static inline int _clip_1d(POINT const *src, unsigned src_num_points,
|
||||
POINT *dst, int clip)
|
||||
{
|
||||
/*
|
||||
* Walk along the polygon edges. Each time when crossing the
|
||||
* clipping border, a new polygon point is created at the
|
||||
* intersection point. All polygon points outside the clipping area
|
||||
* are discarded.
|
||||
*/
|
||||
unsigned dst_num_points = 0;
|
||||
for (unsigned i = 0; i < src_num_points; i++) {
|
||||
|
||||
POINT curr = *src++;
|
||||
POINT next = *src;
|
||||
|
||||
bool curr_inside = CLIPPER::inside(curr, clip);
|
||||
bool next_inside = CLIPPER::inside(next, clip);
|
||||
|
||||
/* add current point to resulting polygon if inside clipping area */
|
||||
if (curr_inside)
|
||||
dst[dst_num_points++] = curr;
|
||||
|
||||
/* add point of intersection when walking outside of the clipping area */
|
||||
if (curr_inside && !next_inside)
|
||||
dst[dst_num_points++] = CLIPPER::clip(curr, next, clip);
|
||||
|
||||
/* add point of intersection when walking inside to the clipping area */
|
||||
if (!curr_inside && next_inside)
|
||||
dst[dst_num_points++] = CLIPPER::clip(curr, next, clip);
|
||||
}
|
||||
|
||||
/* store coordinates of the first point also at the end of the polygon */
|
||||
dst[dst_num_points] = dst[0];
|
||||
|
||||
return dst_num_points;
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
typedef Genode::Rect<> Rect;
|
||||
typedef Genode::Area<> Area;
|
||||
|
||||
/**
|
||||
* Buffers used for storing interpolated attribute values along a left
|
||||
* or right polygon edges.
|
||||
*
|
||||
* The edge buffers are partitioned into subsequent sub buffers with a
|
||||
* size corresponding to the maximum y range of the polygon, which is
|
||||
* the surface height. The different sub buffers are used to hold the
|
||||
* interpolated edge values for the different polygon-point attributes.
|
||||
*
|
||||
* \param N number of attributes
|
||||
*/
|
||||
template <unsigned N>
|
||||
class Edge_buffers
|
||||
{
|
||||
private:
|
||||
|
||||
Genode::Allocator &_alloc;
|
||||
|
||||
unsigned const _edge_len;
|
||||
|
||||
Genode::size_t _edges_size() { return N*2*_edge_len*sizeof(int); }
|
||||
|
||||
int * const _edges = (int *)_alloc.alloc(_edges_size());
|
||||
|
||||
public:
|
||||
|
||||
Edge_buffers(Genode::Allocator &alloc, unsigned edge_len)
|
||||
:
|
||||
_alloc(alloc), _edge_len(edge_len)
|
||||
{ }
|
||||
|
||||
~Edge_buffers() { _alloc.free(_edges, _edges_size()); }
|
||||
|
||||
/**
|
||||
* Return size of a single edge buffer
|
||||
*/
|
||||
unsigned edge_len() const { return _edge_len; }
|
||||
|
||||
/**
|
||||
* Return left edge buffer for Nth attribute
|
||||
*/
|
||||
int *left(unsigned n) { return _edges + n*2*_edge_len; }
|
||||
|
||||
/**
|
||||
* Return right edge buffer for Nth attribute
|
||||
*/
|
||||
int *right(unsigned n) { return _edges + (n*2 + 1)*_edge_len; }
|
||||
};
|
||||
|
||||
/**
|
||||
* Calculate maximum number of points needed for clipped polygon
|
||||
*
|
||||
* When clipping the polygon with 'num_points' points against
|
||||
* the canvas boundaries, the resulting polygon will have a
|
||||
* maximum of 'num_points' + 4 points - in the worst case one
|
||||
* additional point per canvas edge. To ease the further
|
||||
* processing, we add the coordinates of the first point as an
|
||||
* additional point to the clipped polygon.
|
||||
*/
|
||||
static unsigned max_points_clipped(unsigned num_points)
|
||||
{
|
||||
return num_points + 4 + 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Clip polygon against clipping rectangle
|
||||
*
|
||||
* \param src_points Array of unclipped polygon points
|
||||
* \param num_points Number of unclipped polygon points
|
||||
* \param dst_points Buffer for storing the clipped polygon
|
||||
* \return Number of points of resulting polygon
|
||||
*
|
||||
* During the clipping computation, the destination buffer 'dst_points'
|
||||
* is used to store two polygons. Therefore, the buffer must be
|
||||
* dimensioned at 2*'max_points_clipped()'. The end result of the
|
||||
* computation is stored at the beginning of 'dst_points'.
|
||||
*/
|
||||
template <typename POINT>
|
||||
static int clip_polygon(POINT const *src_points, unsigned num_points,
|
||||
POINT *dst_points, Rect clip)
|
||||
{
|
||||
POINT *c0 = dst_points,
|
||||
*c1 = dst_points + max_points_clipped(num_points);
|
||||
|
||||
for (unsigned i = 0; i < num_points; i++)
|
||||
c0[i] = src_points[i];
|
||||
|
||||
/* last point is connected to the first point */
|
||||
c0[num_points] = c0[0];
|
||||
|
||||
/* clip against top, left, bottom, and right clipping boundaries */
|
||||
typedef Clipper_2d<POINT> Clipper;
|
||||
num_points = _clip_1d<typename Clipper::Top> (c0, num_points, c1, clip.y1());
|
||||
num_points = _clip_1d<typename Clipper::Left> (c1, num_points, c0, clip.x1());
|
||||
num_points = _clip_1d<typename Clipper::Bottom>(c0, num_points, c1, clip.y2());
|
||||
num_points = _clip_1d<typename Clipper::Right> (c1, num_points, c0, clip.x2());
|
||||
|
||||
return num_points;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Determine bounding box of the specified polygon points
|
||||
*
|
||||
* \height maximum bounds
|
||||
*/
|
||||
template <typename POINT>
|
||||
static Rect bounding_box(POINT const points[], int num_points, Area area)
|
||||
{
|
||||
int x_min = area.w() - 1, x_max = 0;
|
||||
int y_min = area.h() - 1, y_max = 0;
|
||||
|
||||
for (int i = 0; i < num_points; i++) {
|
||||
x_min = Genode::min(x_min, points[i].x());
|
||||
x_max = Genode::max(x_max, points[i].x());
|
||||
y_min = Genode::min(y_min, points[i].y());
|
||||
y_max = Genode::max(y_max, points[i].y());
|
||||
}
|
||||
|
||||
return Rect(Point_base(x_min, y_min), Point_base(x_max, y_max));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Calculate edge buffers for a polygon
|
||||
*
|
||||
* \param N number of edge attributes
|
||||
*/
|
||||
template <unsigned N, typename POINT>
|
||||
void fill_edge_buffers(Edge_buffers<N> &edges,
|
||||
POINT points[], unsigned num_points)
|
||||
{
|
||||
/* for each edge attribute */
|
||||
for (unsigned i = 0; i < N; i++) {
|
||||
|
||||
int * const l_edge = edges.left(i);
|
||||
int * const r_edge = edges.right(i);
|
||||
|
||||
for (unsigned j = 0; j < num_points; j++) {
|
||||
|
||||
POINT const p1 = points[j];
|
||||
POINT const p2 = points[j + 1];
|
||||
|
||||
/* request attribute values to interpolate */
|
||||
int const p1_attr = p1.edge_attr(i);
|
||||
int const p2_attr = p2.edge_attr(i);
|
||||
|
||||
/* horizontal edge */
|
||||
if (p1.y() == p2.y());
|
||||
|
||||
/* right edge */
|
||||
else if (p1.y() < p2.y())
|
||||
_interpolate(p1_attr, p2_attr, r_edge + p1.y(), p2.y() - p1.y());
|
||||
|
||||
/* left edge */
|
||||
else
|
||||
_interpolate(p2_attr, p1_attr, l_edge + p2.y(), p1.y() - p2.y());
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
#endif /* _INCLUDE__POLYGON_GFX__POLYGON_PAINTER_BASE_H_ */
|
145
repos/gems/include/polygon_gfx/shaded_polygon_painter.h
Normal file
145
repos/gems/include/polygon_gfx/shaded_polygon_painter.h
Normal file
@ -0,0 +1,145 @@
|
||||
/*
|
||||
* \brief Functor for painting shaded polygons
|
||||
* \author Norman Feske
|
||||
* \date 2015-06-19
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2015 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 _INCLUDE__POLYGON_GFX__SHADED_POLYGON_PAINTER_H_
|
||||
#define _INCLUDE__POLYGON_GFX__SHADED_POLYGON_PAINTER_H_
|
||||
|
||||
#include <os/surface.h>
|
||||
#include <polygon_gfx/polygon_painter_base.h>
|
||||
#include <polygon_gfx/interpolate_rgba.h>
|
||||
|
||||
namespace Polygon { class Shaded_painter; }
|
||||
|
||||
|
||||
class Polygon::Shaded_painter : public Polygon::Painter_base
|
||||
{
|
||||
private:
|
||||
|
||||
/**
|
||||
* Edge attribute IDs
|
||||
*/
|
||||
enum Edge_attr { ATTR_X, ATTR_R, ATTR_G, ATTR_B, ATTR_A, NUM_ATTR };
|
||||
|
||||
Edge_buffers<NUM_ATTR> _edges;
|
||||
|
||||
public:
|
||||
|
||||
/**
|
||||
* Polygon point used for RGBA-shaded polygons
|
||||
*/
|
||||
struct Point : Point_base
|
||||
{
|
||||
Color color;
|
||||
|
||||
Point() { }
|
||||
Point(int x, int y, Color color) : Point_base(x, y), color(color) { }
|
||||
|
||||
enum { NUM_EDGE_ATTRIBUTES = NUM_ATTR };
|
||||
|
||||
inline int edge_attr(int id) const
|
||||
{
|
||||
switch (id) {
|
||||
default:
|
||||
case ATTR_X: return Point_base::edge_attr(id);
|
||||
case ATTR_R: return color.r;
|
||||
case ATTR_G: return color.g;
|
||||
case ATTR_B: return color.b;
|
||||
case ATTR_A: return color.a;
|
||||
}
|
||||
}
|
||||
|
||||
inline void edge_attr(int id, int value)
|
||||
{
|
||||
switch (id) {
|
||||
case ATTR_X: Point_base::edge_attr(id, value); return;
|
||||
case ATTR_R: color.r = value; return;
|
||||
case ATTR_G: color.g = value; return;
|
||||
case ATTR_B: color.b = value; return;
|
||||
case ATTR_A: color.a = value; return;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* \param alloc allocator used for allocating edge buffers
|
||||
* \param max_height maximum size of polygon to draw, used to dimension
|
||||
* the edge buffers
|
||||
*/
|
||||
Shaded_painter(Genode::Allocator &alloc, unsigned max_height)
|
||||
:
|
||||
_edges(alloc, max_height)
|
||||
{ }
|
||||
|
||||
/**
|
||||
* Draw polygon with linearly interpolated color
|
||||
*
|
||||
* \param points Array of polygon points
|
||||
* \param num_points Number of polygon points
|
||||
*
|
||||
* The pixel surface and the alpha surface must have the same
|
||||
* dimensions.
|
||||
*/
|
||||
template <typename PT, typename AT>
|
||||
void paint(Genode::Surface<PT> &pixel_surface,
|
||||
Genode::Surface<AT> &alpha_surface,
|
||||
Point const points[], unsigned num_points)
|
||||
{
|
||||
Point clipped[2*max_points_clipped(num_points)];
|
||||
num_points = clip_polygon<Point>(points, num_points, clipped,
|
||||
pixel_surface.clip());
|
||||
|
||||
Rect const bbox = bounding_box(clipped, num_points, pixel_surface.size());
|
||||
|
||||
fill_edge_buffers(_edges, clipped, num_points);
|
||||
|
||||
int * const x_l_edge = _edges.left (ATTR_X);
|
||||
int * const x_r_edge = _edges.right(ATTR_X);
|
||||
int * const r_l_edge = _edges.left (ATTR_R);
|
||||
int * const r_r_edge = _edges.right(ATTR_R);
|
||||
int * const g_l_edge = _edges.left (ATTR_G);
|
||||
int * const g_r_edge = _edges.right(ATTR_G);
|
||||
int * const b_l_edge = _edges.left (ATTR_B);
|
||||
int * const b_r_edge = _edges.right(ATTR_B);
|
||||
int * const a_l_edge = _edges.left (ATTR_A);
|
||||
int * const a_r_edge = _edges.right(ATTR_A);
|
||||
|
||||
/* calculate begin of first destination scanline */
|
||||
unsigned const dst_w = pixel_surface.size().w();
|
||||
PT *dst_pixel = pixel_surface.addr() + dst_w*bbox.y1();
|
||||
AT *dst_alpha = alpha_surface.addr() + dst_w*bbox.y1();
|
||||
|
||||
for (int y = bbox.y1(); y < bbox.y2(); y++) {
|
||||
|
||||
/* read left and right color values from corresponding edge buffers */
|
||||
Color l_color = Color(r_l_edge[y], g_l_edge[y], b_l_edge[y], a_l_edge[y]);
|
||||
Color r_color = Color(r_r_edge[y], g_r_edge[y], b_r_edge[y], a_r_edge[y]);
|
||||
|
||||
int const x_l = x_l_edge[y];
|
||||
int const x_r = x_r_edge[y];
|
||||
|
||||
if (x_l < x_r)
|
||||
interpolate_rgba(l_color, r_color, dst_pixel + x_l,
|
||||
(unsigned char *)dst_alpha + x_l,
|
||||
x_r - x_l, x_l, y);
|
||||
|
||||
dst_pixel += dst_w;
|
||||
dst_alpha += dst_w;
|
||||
}
|
||||
|
||||
pixel_surface.flush_pixels(bbox);
|
||||
}
|
||||
};
|
||||
|
||||
#endif /* _INCLUDE__POLYGON_GFX__SHADED_POLYGON_PAINTER_H_ */
|
146
repos/gems/include/polygon_gfx/textured_polygon_painter.h
Normal file
146
repos/gems/include/polygon_gfx/textured_polygon_painter.h
Normal file
@ -0,0 +1,146 @@
|
||||
/*
|
||||
* \brief Functor for painting textured polygons
|
||||
* \author Norman Feske
|
||||
* \date 2015-06-29
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2015 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 _INCLUDE__POLYGON_GFX__TEXTURED_POLYGON_PAINTER_H_
|
||||
#define _INCLUDE__POLYGON_GFX__TEXTURED_POLYGON_PAINTER_H_
|
||||
|
||||
#include <os/surface.h>
|
||||
#include <os/texture.h>
|
||||
#include <polygon_gfx/polygon_painter_base.h>
|
||||
#include <polygon_gfx/texturize_rgba.h>
|
||||
|
||||
namespace Polygon { class Textured_painter; }
|
||||
|
||||
|
||||
class Polygon::Textured_painter : public Polygon::Painter_base
|
||||
{
|
||||
private:
|
||||
|
||||
/**
|
||||
* Edge attribute IDs
|
||||
*/
|
||||
enum Edge_attr { ATTR_X, ATTR_U, ATTR_V, NUM_ATTR };
|
||||
|
||||
Edge_buffers<NUM_ATTR> _edges;
|
||||
|
||||
public:
|
||||
|
||||
/**
|
||||
* Polygon point used for textured polygons
|
||||
*/
|
||||
struct Point : Point_base
|
||||
{
|
||||
int u = 0, v = 0;
|
||||
|
||||
Point() { }
|
||||
Point(int x, int y, int u, int v) : Point_base(x, y), u(u), v(v) { }
|
||||
|
||||
enum { NUM_EDGE_ATTRIBUTES = NUM_ATTR };
|
||||
|
||||
inline int edge_attr(int id) const
|
||||
{
|
||||
switch (id) {
|
||||
default:
|
||||
case ATTR_X: return Point_base::edge_attr(id);
|
||||
case ATTR_U: return u;
|
||||
case ATTR_V: return v;
|
||||
}
|
||||
}
|
||||
|
||||
inline void edge_attr(int id, int value)
|
||||
{
|
||||
switch (id) {
|
||||
case ATTR_X: Point_base::edge_attr(id, value); return;
|
||||
case ATTR_U: u = value; return;
|
||||
case ATTR_V: v = value; return;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* \param alloc allocator used for allocating edge buffers
|
||||
* \param max_height maximum size of polygon to draw, used to dimension
|
||||
* the edge buffers
|
||||
*/
|
||||
Textured_painter(Genode::Allocator &alloc, unsigned max_height)
|
||||
:
|
||||
_edges(alloc, max_height)
|
||||
{ }
|
||||
|
||||
/**
|
||||
* Draw textured polygon
|
||||
*
|
||||
* \param points Array of polygon points
|
||||
* \param num_points Number of polygon points
|
||||
*
|
||||
* The pixel surface and the alpha surface must have the same
|
||||
* dimensions.
|
||||
*/
|
||||
template <typename PT, typename AT>
|
||||
void paint(Genode::Surface<PT> &pixel_surface,
|
||||
Genode::Surface<AT> &alpha_surface,
|
||||
Point const points[], unsigned num_points,
|
||||
Genode::Texture<PT> const &texture)
|
||||
{
|
||||
Point clipped[2*max_points_clipped(num_points)];
|
||||
num_points = clip_polygon<Point>(points, num_points, clipped,
|
||||
pixel_surface.clip());
|
||||
|
||||
Rect const bbox = bounding_box(clipped, num_points, pixel_surface.size());
|
||||
|
||||
fill_edge_buffers(_edges, clipped, num_points);
|
||||
|
||||
int * const x_l_edge = _edges.left (ATTR_X);
|
||||
int * const x_r_edge = _edges.right(ATTR_X);
|
||||
int * const u_l_edge = _edges.left (ATTR_U);
|
||||
int * const u_r_edge = _edges.right(ATTR_U);
|
||||
int * const v_l_edge = _edges.left (ATTR_V);
|
||||
int * const v_r_edge = _edges.right(ATTR_V);
|
||||
|
||||
unsigned const src_w = texture.size().w();
|
||||
PT const *src_pixel = texture.pixel();
|
||||
unsigned char const *src_alpha = texture.alpha();
|
||||
|
||||
/* calculate begin of destination scanline */
|
||||
unsigned const dst_w = pixel_surface.size().w();
|
||||
PT *dst_pixel = pixel_surface.addr() + dst_w*bbox.y1();
|
||||
AT *dst_alpha = alpha_surface.addr() + dst_w*bbox.y1();
|
||||
|
||||
for (int y = bbox.y1(); y < bbox.y2(); y++) {
|
||||
|
||||
/*
|
||||
* Read left and right texture coordinates (u,v) from
|
||||
* corresponding edge buffers.
|
||||
*/
|
||||
Genode::Point<> const l_texpos(u_l_edge[y], v_l_edge[y]);
|
||||
Genode::Point<> const r_texpos(u_r_edge[y], v_r_edge[y]);
|
||||
|
||||
int const x_l = x_l_edge[y];
|
||||
int const x_r = x_r_edge[y];
|
||||
|
||||
if (x_l < x_r)
|
||||
texturize_rgba(l_texpos, r_texpos,
|
||||
dst_pixel + x_l, (unsigned char *)dst_alpha + x_l,
|
||||
x_r - x_l, src_pixel, src_alpha, src_w);
|
||||
|
||||
dst_pixel += dst_w;
|
||||
dst_alpha += dst_w;
|
||||
}
|
||||
|
||||
pixel_surface.flush_pixels(bbox);
|
||||
}
|
||||
};
|
||||
|
||||
#endif /* _INCLUDE__POLYGON_GFX__TEXTURED_POLYGON_PAINTER_H_ */
|
69
repos/gems/include/polygon_gfx/texturize_rgba.h
Normal file
69
repos/gems/include/polygon_gfx/texturize_rgba.h
Normal file
@ -0,0 +1,69 @@
|
||||
/*
|
||||
* \brief Texturizing function for polygon painting
|
||||
* \date 2015-06-29
|
||||
* \author Norman Feske
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2015 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 _INCLUDE__POLYGON_GFX__TEXTURIZE_RGBA_H_
|
||||
#define _INCLUDE__POLYGON_GFX__TEXTURIZE_RGBA_H_
|
||||
|
||||
/* Genode includes */
|
||||
#include <util/color.h>
|
||||
#include <os/pixel_rgba.h>
|
||||
#include <util/geometry.h>
|
||||
|
||||
namespace Polygon {
|
||||
|
||||
template <typename PT>
|
||||
static inline void texturize_rgba(Genode::Point<>, Genode::Point<>, PT *,
|
||||
unsigned char *, unsigned, PT const *,
|
||||
unsigned char const *, unsigned);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Texturize scanline
|
||||
*/
|
||||
template <typename PT>
|
||||
static inline void Polygon::texturize_rgba(Genode::Point<> start, Genode::Point<> end,
|
||||
PT *dst, unsigned char *dst_alpha,
|
||||
unsigned num_values,
|
||||
PT const *texture_base,
|
||||
unsigned char const *alpha_base,
|
||||
unsigned texture_width)
|
||||
{
|
||||
/* sanity check */
|
||||
if (num_values <= 0) return;
|
||||
|
||||
/* use 16.16 fixpoint values for the calculation */
|
||||
int tx_ascent = ((end.x() - start.x())<<16)/(int)num_values,
|
||||
ty_ascent = ((end.y() - start.y())<<16)/(int)num_values;
|
||||
|
||||
/* set start values for color components */
|
||||
int tx = start.x()<<16,
|
||||
ty = start.y()<<16;
|
||||
|
||||
for ( ; num_values--; dst++, dst_alpha++) {
|
||||
|
||||
/* blend pixel from texture with destination point on surface */
|
||||
unsigned long src_offset = (ty>>16)*texture_width + (tx>>16);
|
||||
|
||||
int const a = alpha_base[src_offset];
|
||||
|
||||
*dst = texture_base[src_offset];
|
||||
*dst_alpha += ((255 - *dst_alpha)*a) >> 8;
|
||||
|
||||
/* walk through texture */
|
||||
tx += tx_ascent;
|
||||
ty += ty_ascent;
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* _INCLUDE__POLYGON_GFX__TEXTURIZE_RGBA_H_ */
|
149
repos/gems/run/nano3d.run
Normal file
149
repos/gems/run/nano3d.run
Normal file
@ -0,0 +1,149 @@
|
||||
#
|
||||
# Build
|
||||
#
|
||||
if {![have_spec linux]} {
|
||||
puts "Runs on Linux only"
|
||||
exit 0
|
||||
}
|
||||
|
||||
set build_components {
|
||||
core init
|
||||
drivers/timer
|
||||
server/nitpicker server/dynamic_rom app/nano3d
|
||||
drivers/framebuffer
|
||||
app/backdrop
|
||||
}
|
||||
|
||||
lappend_if [have_spec usb] build_components drivers/usb
|
||||
|
||||
build $build_components
|
||||
|
||||
create_boot_directory
|
||||
|
||||
#
|
||||
# Generate config
|
||||
#
|
||||
|
||||
append config {
|
||||
<config>
|
||||
<parent-provides>
|
||||
<service name="ROM"/>
|
||||
<service name="RAM"/>
|
||||
<service name="IRQ"/>
|
||||
<service name="IO_MEM"/>
|
||||
<service name="IO_PORT"/>
|
||||
<service name="CAP"/>
|
||||
<service name="PD"/>
|
||||
<service name="RM"/>
|
||||
<service name="CPU"/>
|
||||
<service name="LOG"/>
|
||||
<service name="SIGNAL"/>
|
||||
</parent-provides>
|
||||
<default-route>
|
||||
<any-service> <parent/> <any-child/> </any-service>
|
||||
</default-route>
|
||||
|
||||
<start name="fb_sdl">
|
||||
<resource name="RAM" quantum="4M"/>
|
||||
<provides>
|
||||
<service name="Input"/>
|
||||
<service name="Framebuffer"/>
|
||||
</provides>
|
||||
</start>
|
||||
|
||||
<start name="timer">
|
||||
<resource name="RAM" quantum="1M"/>
|
||||
<provides><service name="Timer"/></provides>
|
||||
</start>
|
||||
|
||||
<start name="nitpicker">
|
||||
<resource name="RAM" quantum="1M"/>
|
||||
<provides><service name="Nitpicker"/></provides>
|
||||
<config>
|
||||
<domain name="" layer="2" />
|
||||
<domain name="nano3d" layer="1" origin="pointer"/>
|
||||
|
||||
<policy label="nano3d" domain="nano3d"/>
|
||||
<policy label="" domain=""/>
|
||||
</config>
|
||||
</start>
|
||||
|
||||
<start name="backdrop">
|
||||
<resource name="RAM" quantum="4M"/>
|
||||
<config>
|
||||
<libc>
|
||||
<vfs>
|
||||
<rom name="genode_logo.png"/>
|
||||
<rom name="grid.png"/>
|
||||
</vfs>
|
||||
</libc>
|
||||
<fill color="#122334" />
|
||||
<image png="grid.png" tiled="yes" alpha="200" />
|
||||
<image png="genode_logo.png" anchor="bottom_right" alpha="150"/>
|
||||
</config>
|
||||
</start>
|
||||
|
||||
<start name="dynamic_rom">
|
||||
<resource name="RAM" quantum="4M"/>
|
||||
<provides><service name="ROM"/></provides>
|
||||
<config verbose="yes">
|
||||
<rom name="nano3d.config">
|
||||
<inline description="initial state">
|
||||
<config painter="textures"/>
|
||||
</inline>
|
||||
<sleep milliseconds="1000" />
|
||||
<inline description="RGBA shading">
|
||||
<config painter="shaded"/>
|
||||
</inline>
|
||||
<sleep milliseconds="1000" />
|
||||
<inline description="switch to cube">
|
||||
<config painter="shaded" shape="cube" />
|
||||
</inline>
|
||||
<sleep milliseconds="1000" />
|
||||
<inline description="texturing">
|
||||
<config painter="textured" shape="cube" />
|
||||
</inline>
|
||||
<sleep milliseconds="1000" />
|
||||
</rom>
|
||||
</config>
|
||||
</start>
|
||||
|
||||
<start name="nano3d">
|
||||
<resource name="RAM" quantum="8M"/>
|
||||
<configfile name="nano3d.config"/>
|
||||
<route>
|
||||
<service name="ROM">
|
||||
<if-arg key="label" value="nano3d.config" />
|
||||
<child name="dynamic_rom" />
|
||||
</service>
|
||||
<any-service> <parent/> <any-child/> </any-service>
|
||||
</route>
|
||||
</start>
|
||||
</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
|
||||
#
|
||||
|
||||
# generic modules
|
||||
set boot_modules {
|
||||
core init
|
||||
timer
|
||||
nitpicker dynamic_rom nano3d
|
||||
backdrop
|
||||
ld.lib.so libpng.lib.so libc.lib.so libm.lib.so zlib.lib.so
|
||||
genode_logo.png grid.png
|
||||
}
|
||||
|
||||
# platform-specific modules
|
||||
lappend_if [have_spec linux] boot_modules fb_sdl
|
||||
|
||||
build_boot_image $boot_modules
|
||||
|
||||
run_genode_until forever
|
235
repos/gems/src/app/nano3d/main.cc
Normal file
235
repos/gems/src/app/nano3d/main.cc
Normal file
@ -0,0 +1,235 @@
|
||||
/*
|
||||
* \brief Animated cube
|
||||
* \author Norman Feske
|
||||
* \date 2015-06-26
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2015 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/config.h>
|
||||
#include <polygon_gfx/shaded_polygon_painter.h>
|
||||
#include <polygon_gfx/interpolate_rgb565.h>
|
||||
#include <polygon_gfx/textured_polygon_painter.h>
|
||||
#include <nano3d/dodecahedron_shape.h>
|
||||
#include <nano3d/cube_shape.h>
|
||||
#include <nano3d/scene.h>
|
||||
#include <nano3d/sqrt.h>
|
||||
|
||||
|
||||
template <typename PT>
|
||||
class Scene : public Nano3d::Scene<PT>
|
||||
{
|
||||
public:
|
||||
|
||||
enum Shape { SHAPE_DODECAHEDRON, SHAPE_CUBE };
|
||||
enum Painter { PAINTER_SHADED, PAINTER_TEXTURED };
|
||||
|
||||
private:
|
||||
|
||||
Nitpicker::Area const _size;
|
||||
|
||||
struct Radial_texture
|
||||
{
|
||||
enum { W = 128, H = 128 };
|
||||
|
||||
unsigned char alpha[H][W];
|
||||
PT pixel[H][W];
|
||||
Genode::Surface_base::Area size { W, H };
|
||||
Genode::Texture<PT> texture { &pixel[0][0], &alpha[0][0], size };
|
||||
|
||||
Radial_texture()
|
||||
{
|
||||
int const r_max = W/2 + 5;
|
||||
|
||||
for (unsigned y = 0; y < H; y++) {
|
||||
for (unsigned x = 0; x < W; x++) {
|
||||
|
||||
int const dx = x - W/2;
|
||||
int const dy = y - H/2;
|
||||
|
||||
int const radius = Nano3d::sqrt(dx*dx + dy*dy);
|
||||
|
||||
alpha[y][x] = 250 - (radius*250)/r_max;
|
||||
|
||||
if ((x&4) ^ (y&4))
|
||||
alpha[y][x] = 0;
|
||||
|
||||
int const r = (x*200)/W;
|
||||
int const g = (y*200)/H;
|
||||
int const b = (x*128)/W + (y*128)/H;
|
||||
|
||||
pixel[y][x] = PT(r, g, b);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
Radial_texture _texture;
|
||||
|
||||
Shape _shape = SHAPE_DODECAHEDRON;
|
||||
Painter _painter = PAINTER_TEXTURED;
|
||||
|
||||
void _handle_config(unsigned)
|
||||
{
|
||||
Genode::config()->reload();
|
||||
|
||||
try {
|
||||
_shape = SHAPE_DODECAHEDRON;
|
||||
if (Genode::config()->xml_node().attribute("shape").has_value("cube"))
|
||||
_shape = SHAPE_CUBE;
|
||||
} catch (...) { }
|
||||
|
||||
try {
|
||||
_painter = PAINTER_TEXTURED;
|
||||
if (Genode::config()->xml_node().attribute("painter").has_value("shaded"))
|
||||
_painter = PAINTER_SHADED;
|
||||
} catch (...) { }
|
||||
}
|
||||
|
||||
Genode::Signal_dispatcher<Scene> _config_dispatcher;
|
||||
|
||||
public:
|
||||
|
||||
Scene(Genode::Signal_receiver &sig_rec, unsigned update_rate_ms,
|
||||
Nitpicker::Point pos, Nitpicker::Area size)
|
||||
:
|
||||
Nano3d::Scene<PT>(sig_rec, update_rate_ms, pos, size), _size(size),
|
||||
_config_dispatcher(sig_rec, *this, &Scene::_handle_config)
|
||||
{
|
||||
Genode::config()->sigh(_config_dispatcher);
|
||||
_handle_config(0);
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
Polygon::Shaded_painter _shaded_painter {
|
||||
*Genode::env()->heap(), _size.h() };
|
||||
Polygon::Textured_painter _textured_painter {
|
||||
*Genode::env()->heap(), _size.h() };
|
||||
|
||||
Nano3d::Cube_shape const _cube { 7000 };
|
||||
Nano3d::Dodecahedron_shape const _dodecahedron { 10000 };
|
||||
|
||||
template <typename SHAPE>
|
||||
void _render_shape(Genode::Surface<PT> &pixel,
|
||||
Genode::Surface<Genode::Pixel_alpha8> &alpha,
|
||||
SHAPE const &shape, unsigned frame,
|
||||
bool backward_facing)
|
||||
{
|
||||
typedef Genode::Color Color;
|
||||
|
||||
auto vertices = shape.vertex_array();
|
||||
|
||||
vertices.rotate_x(frame*1);
|
||||
vertices.rotate_y(frame*2);
|
||||
vertices.rotate_z(frame*3);
|
||||
vertices.project(1600, 800);
|
||||
vertices.translate(200, 200, 0);
|
||||
|
||||
if (_painter == PAINTER_TEXTURED) {
|
||||
|
||||
typedef Polygon::Textured_painter::Point Textured_point;
|
||||
|
||||
shape.for_each_face([&] (unsigned const vertex_indices[],
|
||||
unsigned num_vertices) {
|
||||
|
||||
Textured_point points[num_vertices];
|
||||
|
||||
int angle = -frame*4;
|
||||
for (unsigned i = 0; i < num_vertices; i++) {
|
||||
|
||||
Nano3d::Vertex const vertex = vertices[vertex_indices[i]];
|
||||
|
||||
Textured_point &point =
|
||||
backward_facing ? points[num_vertices - 1 - i]
|
||||
: points[i];
|
||||
|
||||
int const r = _texture.size.w()/2;
|
||||
|
||||
int const u = r + (r*Nano3d::cos_frac16(angle) >> 16);
|
||||
int const v = r + (r*Nano3d::sin_frac16(angle) >> 16);
|
||||
|
||||
angle += Nano3d::Sincos_frac16::STEPS / num_vertices;
|
||||
|
||||
point = Textured_point(vertex.x(), vertex.y(), u, v);
|
||||
}
|
||||
|
||||
_textured_painter.paint(pixel, alpha, points, num_vertices,
|
||||
_texture.texture);
|
||||
});
|
||||
}
|
||||
|
||||
if (_painter == PAINTER_SHADED) {
|
||||
|
||||
typedef Polygon::Shaded_painter::Point Shaded_point;
|
||||
|
||||
shape.for_each_face([&] (unsigned const vertex_indices[],
|
||||
unsigned num_vertices) {
|
||||
|
||||
Shaded_point points[num_vertices];
|
||||
|
||||
for (unsigned i = 0; i < num_vertices; i++) {
|
||||
|
||||
Nano3d::Vertex const v = vertices[vertex_indices[i]];
|
||||
|
||||
Shaded_point &point =
|
||||
backward_facing ? points[num_vertices - 1 - i]
|
||||
: points[i];
|
||||
|
||||
Color const color =
|
||||
backward_facing ? Color(i*10, i*10, i*10, 230 - i*18)
|
||||
: Color(240, 10*i, 0, 10 + i*35);
|
||||
|
||||
point = Shaded_point(v.x(), v.y(), color);
|
||||
}
|
||||
|
||||
_shaded_painter.paint(pixel, alpha,
|
||||
points, num_vertices);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
/**
|
||||
* Scene interface
|
||||
*/
|
||||
void render(Genode::Surface<PT> &pixel,
|
||||
Genode::Surface<Genode::Pixel_alpha8> &alpha) override
|
||||
{
|
||||
unsigned const frame = (this->elapsed_ms()/10) % 1024;
|
||||
|
||||
if (_shape == SHAPE_DODECAHEDRON) {
|
||||
|
||||
_render_shape(pixel, alpha, _dodecahedron, frame, true);
|
||||
_render_shape(pixel, alpha, _dodecahedron, frame, false);
|
||||
|
||||
} else if (_shape == SHAPE_CUBE) {
|
||||
|
||||
_render_shape(pixel, alpha, _cube, frame, true);
|
||||
_render_shape(pixel, alpha, _cube, frame, false);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
static Genode::Signal_receiver sig_rec;
|
||||
|
||||
enum { UPDATE_RATE_MS = 20 };
|
||||
|
||||
static Scene<Genode::Pixel_rgb565>
|
||||
scene(sig_rec, UPDATE_RATE_MS,
|
||||
Nitpicker::Point(-200, -200), Nitpicker::Area(400, 400));
|
||||
|
||||
scene.dispatch_signals_loop(sig_rec);
|
||||
|
||||
return 0;
|
||||
}
|
4
repos/gems/src/app/nano3d/target.mk
Normal file
4
repos/gems/src/app/nano3d/target.mk
Normal file
@ -0,0 +1,4 @@
|
||||
TARGET = nano3d
|
||||
SRC_CC = main.cc
|
||||
LIBS = base config
|
||||
INC_DIR += $(PRG_DIR)
|
Loading…
x
Reference in New Issue
Block a user