Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 10 additions & 2 deletions games/cgol/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
#

config GAMES_CGOL
bool "Conway's Game of Life"
tristate "Conway's Game of Life"
depends on VIDEO_FB
default n
---help---
Expand All @@ -25,7 +25,7 @@ config GAMES_CGOL_PRIORITY

config GAMES_CGOL_STACKSIZE
int "CGOL stack size"
default DEFAULT_TASK_STACKSIZE
default 4096

config GAMES_CGOL_FBDEV
string "CGOL frame buffer device path"
Expand All @@ -34,6 +34,14 @@ config GAMES_CGOL_FBDEV
The frame buffer device path that will be used by default for rendering.
Device path can still be selected from first command line argument.

config GAMES_CGOL_YOFFSET
int "Top framebuffer rows to reserve"
range 0 500000
default 0
---help---
Leave this many rows at the top of the framebuffer unchanged. This
allows a launcher or supervisor to reserve a status or control bar.

config GAMES_CGOL_DBLBUF
bool "CGOL double buffered"
default n
Expand Down
107 changes: 83 additions & 24 deletions games/cgol/cgol_main.c
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@
#include <fcntl.h>
#include <limits.h>
#include <math.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
Expand Down Expand Up @@ -174,6 +175,12 @@ struct fb_state_s
struct fb_videoinfo_s vinfo;
struct fb_planeinfo_s pinfo;
unsigned int scale;

/* Rows reserved for the supervisor. */
Comment thread
xiaoxiang781216 marked this conversation as resolved.

unsigned int abs_yoff;
unsigned int usable_yres;

int fd;
void *fb; /* Real frame buffer */
#ifdef CONFIG_GAMES_CGOL_DBLBUF
Expand All @@ -190,10 +197,20 @@ typedef void (*cell_render_f)(const struct fb_state_s *, uint32_t x,
* Private Data
****************************************************************************/

/* Polled by the render loop for cooperative shutdown. */

static volatile sig_atomic_t g_quit_requested;

/****************************************************************************
* Private Functions
****************************************************************************/

static void quit_signal_handler(int signo)
{
(void)signo;
g_quit_requested = 1;
}

/****************************************************************************
* Name: cgol_init
*
Expand Down Expand Up @@ -515,28 +532,30 @@ static void cgol_advance(unsigned int *map)
static void cgol_render_update(const struct fb_state_s *state)
{
#ifdef CONFIG_FB_UPDATE
struct fb_area_s *full_screen;
struct fb_area_s playfield;
int err;

/* Create an area with the dimensions of the full screen for updating the
* frame buffer after render operations are complete.
*/
/* Update only the game area. */

full_screen.x = 0;
full_screen.y = 0;
full_screen.w = fb_state.vinfo.xres;
full_screen.h = fb_state.vinfo.yres;
playfield.x = 0;
playfield.y = state->abs_yoff;
playfield.w = state->vinfo.xres;
playfield.h = state->usable_yres;
#endif

/* If double buffering, copy the RAM buffer to the frame buffer */
/* Copy only the game area from the double buffer. */

#ifdef CONFIG_GAMES_CGOL_DBLBUF
memcpy(state->fb, state->rambuf, state->pinfo.fblen);
memcpy((FAR uint8_t *)state->fb + state->pinfo.stride * state->abs_yoff,
(FAR uint8_t *)state->rambuf +
state->pinfo.stride * state->abs_yoff,
state->pinfo.stride * state->usable_yres);
#endif

/* If the frame buffer on this device needs explicit updates, do that */

#ifdef CONFIG_FB_UPDATE
err = ioctl(fb_state.fd, FBIO_UPDATE, (uintptr_t)&full_screen);
err = ioctl(state->fd, FBIO_UPDATE, (uintptr_t)&playfield);
if (err < 0)
{
fprintf(stderr, "Couldn't update screen: %d\n", errno);
Expand Down Expand Up @@ -567,9 +586,10 @@ static void cgol_render_clear(const struct fb_state_s *state)
switch (state->pinfo.bpp)
{
case 32:
for (uint32_t y = 0; y < state->pinfo.yres_virtual; y++)
for (uint32_t y = 0; y < state->usable_yres; y++)
{
uint8_t *row = render_buf(state) + state->pinfo.stride * y;
uint8_t *row = render_buf(state) +
state->pinfo.stride * (y + state->abs_yoff);
for (uint32_t x = 0; x < state->pinfo.xres_virtual; x++)
{
((uint32_t *)(row))[x] = BG32;
Expand All @@ -578,9 +598,10 @@ static void cgol_render_clear(const struct fb_state_s *state)
break;

case 24:
for (uint32_t y = 0; y < state->pinfo.yres_virtual; y++)
for (uint32_t y = 0; y < state->usable_yres; y++)
{
uint8_t *row = render_buf(state) + state->pinfo.stride * y;
uint8_t *row = render_buf(state) +
state->pinfo.stride * (y + state->abs_yoff);
for (uint32_t x = 0; x < state->pinfo.xres_virtual; x++)
{
*row++ = RGB24BLUE(BG24);
Expand All @@ -592,9 +613,10 @@ static void cgol_render_clear(const struct fb_state_s *state)

case 16:
{
for (uint32_t y = 0; y < state->pinfo.yres_virtual; y++)
for (uint32_t y = 0; y < state->usable_yres; y++)
{
uint8_t *row = render_buf(state) + state->pinfo.stride * y;
uint8_t *row = render_buf(state) +
state->pinfo.stride * (y + state->abs_yoff);
for (uint32_t x = 0; x < state->pinfo.xres_virtual; x++)
{
((uint16_t *)(row))[x] = BG16;
Expand All @@ -604,7 +626,12 @@ static void cgol_render_clear(const struct fb_state_s *state)
break;

case 8:
memset(render_buf(state), BG8, state->pinfo.fblen);
for (uint32_t y = 0; y < state->usable_yres; y++)
{
uint8_t *row = render_buf(state) +
state->pinfo.stride * (y + state->abs_yoff);
memset(row, BG8, state->pinfo.xres_virtual);
}
break;
}
}
Expand Down Expand Up @@ -633,6 +660,8 @@ static void cgol_render_cell8(const struct fb_state_s *state, uint32_t x,
x *= state->scale;
y *= state->scale;

y += state->abs_yoff;

/* Starting at the (x, y) pair, we draw `scale` cells in each direction */

for (uint8_t yy = 0; yy < state->scale; yy++)
Expand Down Expand Up @@ -671,6 +700,8 @@ static void cgol_render_cell16(const struct fb_state_s *state, uint32_t x,
x *= state->scale;
y *= state->scale;

y += state->abs_yoff;

/* Starting at the (x, y) pair, we draw `scale` cells in each direction */

for (uint8_t yy = 0; yy < state->scale; yy++)
Expand Down Expand Up @@ -709,6 +740,8 @@ static void cgol_render_cell24(const struct fb_state_s *state, uint32_t x,
x *= state->scale;
y *= state->scale;

y += state->abs_yoff;

/* Starting at the (x, y) pair, we draw `scale` cells in each direction */

for (uint8_t yy = 0; yy < state->scale; yy++)
Expand Down Expand Up @@ -749,6 +782,8 @@ static void cgol_render_cell32(const struct fb_state_s *state, uint32_t x,
x *= state->scale;
y *= state->scale;

y += state->abs_yoff;

/* Starting at the (x, y) pair, we draw `scale` cells in each direction */

for (uint8_t yy = 0; yy < state->scale; yy++)
Expand Down Expand Up @@ -914,6 +949,17 @@ int main(int argc, FAR char *argv[])
unsigned int map[WORD_COUNT];
unsigned int yscale;
unsigned int xscale;
struct sigaction sa;

g_quit_requested = 0;
memset(&sa, 0, sizeof(sa));
sa.sa_handler = quit_signal_handler;
sigemptyset(&sa.sa_mask);
if (sigaction(SIGTERM, &sa, NULL) < 0)
{
fprintf(stderr, "Failed to install SIGTERM handler: %d\n", errno);
return EXIT_FAILURE;
}

if (argc == 2)
{
Expand Down Expand Up @@ -949,16 +995,25 @@ int main(int argc, FAR char *argv[])
return EXIT_FAILURE;
}

/* Leave the configured supervisor rows untouched. */

fb_state.abs_yoff = CONFIG_GAMES_CGOL_YOFFSET;

/* If the frame buffer resolution is too small to support our game at its
* lowest resolution (one pixel per cell), we can't play :(
*/

if (fb_state.vinfo.xres < CONFIG_GAMES_CGOL_MAPWIDTH ||
fb_state.vinfo.yres < CONFIG_GAMES_CGOL_MAPHEIGHT)
fb_state.vinfo.yres <
CONFIG_GAMES_CGOL_MAPHEIGHT + fb_state.abs_yoff ||
fb_state.pinfo.xres_virtual < CONFIG_GAMES_CGOL_MAPWIDTH ||
fb_state.pinfo.yres_virtual <
CONFIG_GAMES_CGOL_MAPHEIGHT + fb_state.abs_yoff)
{
fprintf(stderr,
"Needed at least %u x %u px resolution, but got %u x %u",
CONFIG_GAMES_CGOL_MAPWIDTH, CONFIG_GAMES_CGOL_MAPHEIGHT,
"Needed at least %u x %u px resolution, but got %u x %u\n",
CONFIG_GAMES_CGOL_MAPWIDTH,
CONFIG_GAMES_CGOL_MAPHEIGHT + fb_state.abs_yoff,
fb_state.vinfo.xres, fb_state.vinfo.yres);
close(fb_state.fd);
return EXIT_FAILURE;
Expand Down Expand Up @@ -1001,6 +1056,7 @@ int main(int argc, FAR char *argv[])
if (fb_state.rambuf == NULL)
{
fprintf(stderr, "Couldn't allocate double buffer: %d\n", errno);
munmap(fb_state.fb, fb_state.pinfo.fblen);
close(fb_state.fd);
return EXIT_FAILURE;
}
Expand All @@ -1012,8 +1068,10 @@ int main(int argc, FAR char *argv[])
* This is selected by picking the minimum of the scale options.
*/

fb_state.usable_yres = fb_state.pinfo.yres_virtual - fb_state.abs_yoff;

xscale = fb_state.pinfo.xres_virtual / CONFIG_GAMES_CGOL_MAPWIDTH;
yscale = fb_state.pinfo.yres_virtual / CONFIG_GAMES_CGOL_MAPHEIGHT;
yscale = fb_state.usable_yres / CONFIG_GAMES_CGOL_MAPHEIGHT;
fb_state.scale = xscale < yscale ? xscale : yscale;

/* Now we can seed the game with some random starting cells */
Expand All @@ -1024,9 +1082,9 @@ int main(int argc, FAR char *argv[])

cgol_render_clear(&fb_state);

/* Loop the game forever */
/* Loop the game until asked to quit */

for (; ; )
while (!g_quit_requested)
{
/* Render the freshly calculated cells */

Expand All @@ -1052,6 +1110,7 @@ int main(int argc, FAR char *argv[])
#ifdef CONFIG_GAMES_CGOL_DBLBUF
free(fb_state.rambuf);
#endif
munmap(fb_state.fb, fb_state.pinfo.fblen);
close(fb_state.fd);
return EXIT_SUCCESS;
}
2 changes: 1 addition & 1 deletion games/match4/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
#

config GAMES_MATCH4
bool "Match 4 Game"
tristate "Match 4 Game"
default n
---help---
Enable Match 4 game.
Expand Down
2 changes: 1 addition & 1 deletion games/snake/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
#

config GAMES_SNAKE
bool "Snake Game"
tristate "Snake Game"
default n
---help---
Enable Snake game.
Expand Down
Loading