259b127f96
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).
236 lines
5.8 KiB
C++
236 lines
5.8 KiB
C++
/*
|
|
* \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;
|
|
}
|