added a program that displays julia fractals

Issue #109
This commit is contained in:
Daniel Collins
2018-06-26 12:18:51 +02:00
committed by Norman Feske
parent 62de16158d
commit e6ee017e18
3 changed files with 280 additions and 0 deletions

85
run/julia_fractal.run Normal file
View File

@@ -0,0 +1,85 @@
create_boot_directory
import_from_depot genodelabs/pkg/wm
build "core init drivers/timer server/nitpicker server/wm app/julia_fractal"
# Only supports the linux kernel, for now;
# instantiates an fb_sdl explicitly, rather than using custom code or a package.
install_config {
<config>
<parent-provides>
<service name="IO_MEM"/>
<service name="IO_PORT"/>
<service name="IRQ"/>
<service name="ROM"/>
<service name="PD"/>
<service name="RM"/>
<service name="RAM"/>
<service name="CPU"/>
<service name="LOG"/>
</parent-provides>
<default-route>
<any-service> <parent/> <any-child/> </any-service>
</default-route>
<default caps="125"/>
<start name="julia_fractal">
<resource name="RAM" quantum="4M"/>
<route>
<service name="Nitpicker"> <child name="wm"/> </service>
<any-service> <parent/> <any-child/> </any-service>
</route>
</start>
<!-- Nitpicker -->
<start name="timer">
<resource name="RAM" quantum="1M"/>
<provides> <service name="Timer"/> </provides>
</start>
<start name="fb_sdl">
<resource name="RAM" quantum="8M"/>
<provides>
<service name="Input"/>
<service name="Framebuffer"/>
</provides>
</start>
<start name="nitpicker">
<resource name="RAM" quantum="2M"/>
<provides> <service name="Nitpicker"/> </provides>
<config focus="rom">
<domain name="pointer" layer="1" content="client" label="no" origin="pointer"/>
<domain name="general" layer="2" content="client" label="no" hover="always"/>
<policy label_prefix="pointer" domain="pointer"/>
<default-policy domain="general"/>
</config>
</start>
<start name="pointer">
<resource name="RAM" quantum="2M"/>
<route>
<service name="Nitpicker"> <child name="nitpicker"/> </service>
<any-service> <parent/> <any-child/> </any-service>
</route>
</start>
<start name="wm" caps="1000">
<resource name="RAM" quantum="32M"/>
<binary name="init"/>
<provides> <service name="Nitpicker"/> </provides>
<route>
<service name="ROM" label="config"> <parent label="wm.config"/> </service>
<service name="Nitpicker"> <child name="nitpicker"/> </service>
<any-service> <parent/> <any-child/> </any-service>
</route>
</start>
</config>
}
set fd [open [run_dir]/genode/focus w]
puts $fd "<focus label=\"wm -> wm -> \"/>"
close $fd
build_boot_image "core ld.lib.so libc.lib.so vfs.lib.so libm.lib.so stdcxx.lib.so init timer fb_sdl nitpicker wm pointer julia_fractal"
run_genode_until forever

View File

@@ -0,0 +1,191 @@
/*
* \brief Displays julia sets and responds to mode resize events
* \author Daniel Collins
* \date 2018-06-22
*
* Creates a pretty animation by drawing successive julia set representations,
* periodically varying a constant factor.
*
* The program responds to mode changes. Hence, one can resize the Julia window.
*/
/*
* Copyright (C) 2018 Daniel Collins
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
* files (the "Software"), to deal in the Software without
* restriction, including without limitation the rights to use,
* copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following
* conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*/
#include <base/component.h>
#include <base/log.h>
#include <os/pixel_rgb565.h>
#include <base/attached_dataspace.h>
#include <timer_session/connection.h>
#include <nitpicker_session/connection.h>
#include <libc/component.h>
#include <complex> // STL
struct Painter_T {
virtual ~Painter_T() = default;
virtual void paint(Genode::Pixel_rgb565*, unsigned w, unsigned h) = 0;
};
class window {
using View_handle = Nitpicker::Session::View_handle;
using Reattachable_dataspace = Genode::Constructible<Genode::Attached_dataspace>;
Genode::Env& _env;
Nitpicker::Connection _npconn;
Framebuffer::Mode _mode;
Painter_T& _draw;
Reattachable_dataspace _ds{};
View_handle _view{};
void _draw_frame() {
_draw.paint(_ds->local_addr<Genode::Pixel_rgb565>(), _mode.width(), _mode.height()); }
void _refresh() {
_npconn.framebuffer()->refresh(0, 0, _mode.width(), _mode.height()); }
void _new_mode() {
_mode = _npconn.mode();
_npconn.buffer(_mode, false);
_ds.construct(_env.rm(), _npconn.framebuffer()->dataspace());
_draw_frame();
_refresh();
auto rect = Nitpicker::Rect{Nitpicker::Point{0, 0},
Nitpicker::Area{(unsigned)_mode.width(),
(unsigned)_mode.height()}};
_npconn.enqueue<Nitpicker::Session::Command::Geometry>(_view, rect);
_npconn.execute();
}
Genode::Signal_handler<window> _on_resize{_env.ep(), *this, &window::_new_mode};
public:
using Title_String_T = Genode::String<64>;
~window() = default;
window() = delete;
window(Genode::Env& env, Painter_T& painter,
Title_String_T title, Nitpicker::Area wsize)
: _env{env}, _npconn{env},
_mode{(int)wsize.w(), (int)wsize.h(), Framebuffer::Mode::RGB565},
_draw{painter}, _ds{env.rm(), _npconn.framebuffer()->dataspace()}
{
using Nitpicker::Session;
_npconn.buffer(_mode, false);
_view = _npconn.create_view();
_new_mode(); /* Get the newest mode+buffer and start drawing */
_npconn.enqueue<Session::Command::Title>(_view, title);
_npconn.enqueue<Session::Command::To_front>(_view, View_handle{});
_npconn.execute();
_npconn.mode_sigh(_on_resize);
}
void draw_next_frame() {
_draw_frame();
_refresh();
}
};
class julia : public Painter_T {
using flt_t = double;
using cmplx = std::complex<flt_t>;
public:
/** Changed using direct assignment **/
flt_t C;
unsigned N;
virtual ~julia() = default;
julia(flt_t c, unsigned n) : C{c}, N{n} {}
/**
* Draw a calculated set in the buffer.
*/
virtual void paint(Genode::Pixel_rgb565* buf, unsigned w, unsigned h)
{
--w, --h;
const auto _w = w;
const auto _h = h;
Genode::size_t idx{0};
do do {
/// Scale pixels
cmplx Z {w*3.5/_w - 1.75, h*2.0/_h - 1};
unsigned i {0};
for (; i < N && (Z.real()*Z.real() + Z.imag()*Z.imag()) < 4.0; ++i)
Z = Z*Z + C;
unsigned c = ((i)*255) / N;
if (i < N) {
double quotient = ((double) i) / N;
if (quotient > 0.5)
buf[idx++].rgba(255, c, c);
else
buf[idx++].rgba(c, 0, 0);
} else buf[idx++].rgba(0, 0, 0);
} while (w-- > 0); while (w = _w, h-- > 0);
}
};
/**
* Calls a functor on an interval
*/
template <typename Fn_T>
class Timer_callback {
Genode::Env& _env;
Timer::Connection _timer{_env};
Fn_T _callback;
void _call() { _callback(); }
Genode::Signal_handler<Timer_callback<Fn_T>> _time_sigh {
_env.ep(), *this, &Timer_callback::_call };
public:
Timer_callback(Genode::Env& env, unsigned interval, Fn_T func)
: _env{env}, _callback{func} {
_timer.sigh(_time_sigh);
_timer.trigger_periodic(interval);
}
};
void Libc::Component::construct(Libc::Env& env) {
static julia painter{-.75, 20};
static window win{env, painter, "julia", Nitpicker::Area{256, 256}};
auto update_win = [&] {
painter.C -= 0.003;
win.draw_next_frame();
};
/* Update the window's contents on a static interval. */
static Timer_callback<decltype(update_win)>
window_update_timer{env, 15000, update_win};
Genode::log("constructed");
}

View File

@@ -0,0 +1,4 @@
TARGET = julia_fractal
SRC_CC = main.cc
LIBS += base
LIBS += stdcxx # evil!