gol: Use the windowing system
This commit is contained in:
parent
52b04bd33b
commit
b09226b8ba
@ -38,6 +38,7 @@ luna_app(sysfuzz.cpp sysfuzz)
|
|||||||
luna_app(cp.cpp cp)
|
luna_app(cp.cpp cp)
|
||||||
luna_app(kill.cpp kill)
|
luna_app(kill.cpp kill)
|
||||||
luna_app(gol.cpp gol)
|
luna_app(gol.cpp gol)
|
||||||
|
target_link_libraries(gol PUBLIC ui)
|
||||||
luna_app(touch.cpp touch)
|
luna_app(touch.cpp touch)
|
||||||
luna_app(free.cpp free)
|
luna_app(free.cpp free)
|
||||||
luna_app(about.cpp about)
|
luna_app(about.cpp about)
|
||||||
|
117
apps/gol.cpp
117
apps/gol.cpp
@ -1,13 +1,12 @@
|
|||||||
#include <alloca.h>
|
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
#include <luna/Heap.h>
|
#include <luna/Heap.h>
|
||||||
#include <os/ArgumentParser.h>
|
#include <os/ArgumentParser.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <sys/ioctl.h>
|
|
||||||
#include <sys/mman.h>
|
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
|
#include <ui/App.h>
|
||||||
|
#include <ui/Window.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
struct Cell
|
struct Cell
|
||||||
@ -16,16 +15,12 @@ struct Cell
|
|||||||
bool new_state;
|
bool new_state;
|
||||||
};
|
};
|
||||||
|
|
||||||
static int g_num_rows = 76;
|
static int g_num_rows = 40;
|
||||||
static int g_num_columns = 102;
|
static int g_num_columns = 60;
|
||||||
|
|
||||||
static int g_fb_width;
|
|
||||||
static int g_fb_height;
|
|
||||||
|
|
||||||
static int g_fd;
|
|
||||||
|
|
||||||
static Cell* g_cells;
|
static Cell* g_cells;
|
||||||
static char* g_fb;
|
|
||||||
|
static ui::Window* g_window;
|
||||||
|
|
||||||
static Result<void> fill_cells()
|
static Result<void> fill_cells()
|
||||||
{
|
{
|
||||||
@ -47,31 +42,30 @@ static Cell& find_cell(int row, int column)
|
|||||||
return g_cells[row * g_num_columns + column];
|
return g_cells[row * g_num_columns + column];
|
||||||
}
|
}
|
||||||
|
|
||||||
static constexpr int BYTES_PER_PIXEL = 4;
|
static constexpr int BYTES_PER_PIXEL = sizeof(u32);
|
||||||
|
static constexpr ui::Color activated_cell_color = ui::CYAN;
|
||||||
|
static constexpr ui::Color deactivated_cell_color = ui::Color::from_rgb(40, 40, 40);
|
||||||
|
|
||||||
static void draw_cells()
|
static void draw_cells()
|
||||||
{
|
{
|
||||||
const int CELL_WIDTH = g_fb_width / g_num_columns;
|
const int CELL_WIDTH = g_window->canvas().width / g_num_columns;
|
||||||
const int CELL_HEIGHT = g_fb_height / g_num_rows;
|
const int CELL_HEIGHT = g_window->canvas().height / g_num_rows;
|
||||||
|
|
||||||
|
auto canvas = g_window->canvas();
|
||||||
|
|
||||||
for (int i = 0; i < g_num_rows; i++)
|
for (int i = 0; i < g_num_rows; i++)
|
||||||
{
|
{
|
||||||
|
|
||||||
for (int j = 0; j < g_num_columns; j++)
|
for (int j = 0; j < g_num_columns; j++)
|
||||||
{
|
{
|
||||||
char* buf = g_fb + (i * g_fb_width * CELL_HEIGHT * BYTES_PER_PIXEL);
|
auto subcanvas = canvas.subcanvas(ui::Rect { j * CELL_WIDTH, i * CELL_HEIGHT, CELL_WIDTH, CELL_HEIGHT });
|
||||||
|
|
||||||
auto& cell = find_cell(i, j);
|
auto& cell = find_cell(i, j);
|
||||||
u8 color = cell.state ? 0xff : 0x00;
|
ui::Color color = cell.state ? activated_cell_color : deactivated_cell_color;
|
||||||
for (int k = 0; k < CELL_HEIGHT; k++)
|
subcanvas.fill(color);
|
||||||
{
|
|
||||||
memset(buf + (j * CELL_WIDTH * BYTES_PER_PIXEL), color, CELL_WIDTH * BYTES_PER_PIXEL);
|
|
||||||
buf += g_fb_width * BYTES_PER_PIXEL;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
msync(g_fb, g_fb_height * g_fb_width * BYTES_PER_PIXEL, MS_SYNC);
|
g_window->update();
|
||||||
}
|
}
|
||||||
|
|
||||||
static int find_neighbors(int row, int column)
|
static int find_neighbors(int row, int column)
|
||||||
@ -109,71 +103,30 @@ static void next_generation()
|
|||||||
|
|
||||||
Result<int> luna_main(int argc, char** argv)
|
Result<int> luna_main(int argc, char** argv)
|
||||||
{
|
{
|
||||||
u64 delay_between_iterations = 250;
|
ui::App app;
|
||||||
u64 delay_at_end = 3000;
|
TRY(app.init(argc, argv));
|
||||||
u64 num_iterations = 100;
|
app.set_nonblocking();
|
||||||
|
|
||||||
StringView columns;
|
g_window = TRY(ui::Window::create(ui::Rect { 200, 200, 600, 400 }));
|
||||||
StringView rows;
|
g_window->set_title("Game of Life");
|
||||||
StringView delay;
|
app.set_main_window(g_window);
|
||||||
StringView end_delay;
|
|
||||||
StringView iterations;
|
|
||||||
StringView seed;
|
|
||||||
|
|
||||||
os::ArgumentParser parser;
|
|
||||||
parser.add_description("A framebuffer-based implementation for Conway's Game of Life.");
|
|
||||||
parser.add_system_program_info("gol"_sv);
|
|
||||||
parser.add_positional_argument(rows, "rows"_sv, "76"_sv);
|
|
||||||
parser.add_positional_argument(columns, "columns"_sv, "102"_sv);
|
|
||||||
parser.add_value_argument(delay, 'd', "delay"_sv, "the delay between generations (in ms)");
|
|
||||||
parser.add_value_argument(end_delay, 'e', "end-delay"_sv,
|
|
||||||
"after finishing, how much to wait before returning to the shell (in ms)");
|
|
||||||
parser.add_value_argument(iterations, 'i', "iterations"_sv, "how many generations to show (default: 100)");
|
|
||||||
parser.add_value_argument(seed, 's', "seed"_sv, "the seed for the random number generator");
|
|
||||||
parser.parse(argc, argv);
|
|
||||||
|
|
||||||
g_num_columns = (int)TRY(columns.to_uint());
|
|
||||||
g_num_rows = (int)TRY(rows.to_uint());
|
|
||||||
if (!delay.is_empty()) delay_between_iterations = TRY(delay.to_uint());
|
|
||||||
if (!end_delay.is_empty()) delay_at_end = TRY(end_delay.to_uint());
|
|
||||||
if (!iterations.is_empty()) num_iterations = TRY(iterations.to_uint());
|
|
||||||
if (!seed.is_empty()) srand((unsigned)TRY(seed.to_uint()));
|
|
||||||
else
|
|
||||||
srand((unsigned)time(NULL));
|
|
||||||
|
|
||||||
g_fd = open("/dev/fb0", O_RDWR);
|
|
||||||
if (g_fd < 0)
|
|
||||||
{
|
|
||||||
perror("gol: cannot open framebuffer for writing");
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
g_fb_height = ioctl(g_fd, FB_GET_HEIGHT);
|
|
||||||
g_fb_width = ioctl(g_fd, FB_GET_WIDTH);
|
|
||||||
|
|
||||||
TRY(fill_cells());
|
TRY(fill_cells());
|
||||||
|
|
||||||
g_fb =
|
int counter = 0;
|
||||||
(char*)mmap(nullptr, g_fb_height * g_fb_width * BYTES_PER_PIXEL, PROT_READ | PROT_WRITE, MAP_SHARED, g_fd, 0);
|
|
||||||
if (g_fb == MAP_FAILED)
|
while (app.process_events())
|
||||||
{
|
{
|
||||||
perror("gol: cannot map framebuffer into memory");
|
if (counter >= 10)
|
||||||
return 1;
|
{
|
||||||
|
next_generation();
|
||||||
|
draw_cells();
|
||||||
|
counter = 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
counter++;
|
||||||
|
usleep(10000);
|
||||||
}
|
}
|
||||||
|
|
||||||
draw_cells();
|
|
||||||
|
|
||||||
while (num_iterations--)
|
|
||||||
{
|
|
||||||
usleep(delay_between_iterations * 1000);
|
|
||||||
next_generation();
|
|
||||||
draw_cells();
|
|
||||||
}
|
|
||||||
|
|
||||||
usleep(delay_at_end * 1000);
|
|
||||||
|
|
||||||
munmap(g_fb, g_fb_height * g_fb_width * BYTES_PER_PIXEL);
|
|
||||||
free(g_cells);
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user