let neko run around

This commit is contained in:
Leon Henrik Plickat 2023-08-13 03:08:56 +02:00
commit abba39daf9

161
wayneko.c
View file

@ -22,12 +22,17 @@
#endif #endif
#endif #endif
#define MIN(A, B) (A < B ? A : B)
#include "wlr-layer-shell-unstable-v1.h" #include "wlr-layer-shell-unstable-v1.h"
pixman_color_t bg_colour;
pixman_color_t border_colour;
/* Note: Atlas width must be divisable by 4. */ /* Note: Atlas width must be divisable by 4. */
#include "neko-bitmap.xbm" #include "neko-bitmap.xbm"
const int neko_bitmap_stride = neko_bitmap_width / 8; const int neko_bitmap_stride = neko_bitmap_width / 8;
const int neko_size = 32; const uint8_t neko_size = 32;
pixman_image_t *neko_atlas = NULL; pixman_image_t *neko_atlas = NULL;
pixman_image_t *neko_atlas_bg_fill = NULL; pixman_image_t *neko_atlas_bg_fill = NULL;
pixman_image_t *neko_atlas_border_fill = NULL; pixman_image_t *neko_atlas_border_fill = NULL;
@ -70,14 +75,15 @@ struct Surface
{ {
struct wl_surface *wl_surface; struct wl_surface *wl_surface;
struct zwlr_layer_surface_v1 *layer_surface; struct zwlr_layer_surface_v1 *layer_surface;
uint32_t width, height;
uint16_t neko_x, prev_neko_x;
bool configured; bool configured;
}; };
struct Surface surface = { 0 }; struct Surface surface = { 0 };
// TODO wide surface and let the neko run around. const uint32_t desired_surface_height = neko_size;
const uint32_t surface_width = neko_size; const uint8_t neko_x_advance = 15;
const uint32_t surface_height = neko_size;
int ret = EXIT_SUCCESS; int ret = EXIT_SUCCESS;
bool loop = true; bool loop = true;
@ -429,25 +435,6 @@ static void buffer_pool_destroy_all_buffers (void)
* Atlas * * Atlas *
* * * *
***********/ ***********/
static bool colour_from_hex (pixman_color_t *colour, const char *hex)
{
uint16_t r = 0, g = 0, b = 0, a = 255;
if ( 4 != sscanf(hex, "0x%02hx%02hx%02hx%02hx", &r, &g, &b, &a)
&& 3 != sscanf(hex, "0x%02hx%02hx%02hx", &r, &g, &b) )
{
fprintf(stderr, "ERROR: Invalid colour: %s\n", hex);
return false;
}
colour->alpha = (uint16_t)(((double)a / 255.0) * 65535.0);
colour->red = (uint16_t)((((double)r / 255.0) * 65535.0) * colour->alpha / 0xffff);
colour->green = (uint16_t)((((double)g / 255.0) * 65535.0) * colour->alpha / 0xffff);
colour->blue = (uint16_t)((((double)b / 255.0) * 65535.0) * colour->alpha / 0xffff);
return true;
}
static void atlas_deinit (void) static void atlas_deinit (void)
{ {
if ( neko_atlas != NULL ) if ( neko_atlas != NULL )
@ -482,8 +469,6 @@ static bool atlas_init (void)
return false; return false;
} }
pixman_color_t bg_colour;
colour_from_hex(&bg_colour, "0xFFFFFF");
neko_atlas_bg_fill = pixman_image_create_solid_fill(&bg_colour); neko_atlas_bg_fill = pixman_image_create_solid_fill(&bg_colour);
if ( neko_atlas_bg_fill == NULL ) if ( neko_atlas_bg_fill == NULL )
{ {
@ -492,8 +477,6 @@ static bool atlas_init (void)
return false; return false;
} }
pixman_color_t border_colour;
colour_from_hex(&border_colour, "0x000000");
neko_atlas_border_fill = pixman_image_create_solid_fill(&border_colour); neko_atlas_border_fill = pixman_image_create_solid_fill(&border_colour);
if ( neko_atlas_border_fill == NULL ) if ( neko_atlas_border_fill == NULL )
{ {
@ -537,6 +520,16 @@ static void atlas_composite_neko (struct Buffer *buffer, enum Neko neko_type, ui
); );
} }
static bool animation_can_run_left (void)
{
return surface.neko_x > neko_x_advance;
}
static bool animation_can_run_right (void)
{
return surface.neko_x < surface.width - neko_size;
}
/** Returns true if new frame is needed. */ /** Returns true if new frame is needed. */
static bool animation_next_state (void) static bool animation_next_state (void)
{ {
@ -570,11 +563,73 @@ static bool animation_next_state (void)
animation_ticks_until_next_frame = 15; animation_ticks_until_next_frame = 15;
return true; return true;
case 4:
if (!animation_can_run_left())
return false;
current_neko = NEKO_RUN_LEFT_1;
surface.prev_neko_x = surface.neko_x;
surface.neko_x -= neko_x_advance;
return true;
case 5:
if (!animation_can_run_right())
return false;
current_neko = NEKO_RUN_RIGHT_1;
surface.prev_neko_x = surface.neko_x;
surface.neko_x += neko_x_advance;
return true;
default: default:
return false; return false;
} }
break; break;
case NEKO_RUN_RIGHT_1:
case NEKO_RUN_RIGHT_2:
case NEKO_RUN_LEFT_1:
case NEKO_RUN_LEFT_2:
if ( current_neko == NEKO_RUN_LEFT_1 || current_neko == NEKO_RUN_LEFT_2 )
{
if (!animation_can_run_left())
{
current_neko = NEKO_STARE;
animation_ticks_until_next_frame = 10;
return true;
}
}
else
{
if (!animation_can_run_right())
{
current_neko = NEKO_STARE;
animation_ticks_until_next_frame = 10;
return true;
}
}
if ( rand() % 4 == 0 )
{
current_neko = NEKO_STARE;
animation_ticks_until_next_frame = 10;
}
else
{
switch (current_neko)
{
case NEKO_RUN_RIGHT_1: current_neko = NEKO_RUN_RIGHT_2; break;
case NEKO_RUN_RIGHT_2: current_neko = NEKO_RUN_RIGHT_1; break;
case NEKO_RUN_LEFT_1: current_neko = NEKO_RUN_LEFT_2; break;
case NEKO_RUN_LEFT_2: current_neko = NEKO_RUN_LEFT_1; break;
default: /* unreachable. */ break;
}
surface.prev_neko_x = surface.neko_x;
if ( current_neko == NEKO_RUN_LEFT_1 || current_neko == NEKO_RUN_LEFT_2 )
surface.neko_x -= neko_x_advance;
else
surface.neko_x += neko_x_advance;
}
return true;
case NEKO_SLEEP_1: case NEKO_SLEEP_1:
case NEKO_SLEEP_2: case NEKO_SLEEP_2:
case NEKO_SCRATCH_1: case NEKO_SCRATCH_1:
@ -655,15 +710,21 @@ static void surface_next_frame (void)
{ {
if (!surface.configured) if (!surface.configured)
return; return;
struct Buffer *buffer = buffer_pool_next_buffer(surface_width, surface_height); struct Buffer *buffer = buffer_pool_next_buffer(surface.width, surface.height);
if ( buffer == NULL ) if ( buffer == NULL )
return; return;
atlas_composite_neko(buffer, current_neko, 0, 0); pixman_image_fill_rectangles(PIXMAN_OP_CLEAR, buffer->pixman_image, &bg_colour,
1, &(pixman_rectangle16_t){ (int16_t)surface.prev_neko_x, (int16_t)0, (uint16_t)neko_size, (uint16_t)neko_size, });
atlas_composite_neko(buffer, current_neko, surface.neko_x, 0);
wl_surface_set_buffer_scale(surface.wl_surface, 1); wl_surface_set_buffer_scale(surface.wl_surface, 1);
wl_surface_attach(surface.wl_surface, buffer->wl_buffer, 0, 0); wl_surface_attach(surface.wl_surface, buffer->wl_buffer, 0, 0);
wl_surface_damage_buffer(surface.wl_surface, 0, 0, INT32_MAX, INT32_MAX); wl_surface_damage_buffer(
surface.wl_surface,
MIN(surface.neko_x, surface.prev_neko_x), 0,
neko_size + neko_x_advance, neko_size
);
buffer->busy = true; buffer->busy = true;
wl_surface_commit(surface.wl_surface); wl_surface_commit(surface.wl_surface);
} }
@ -683,10 +744,17 @@ static void layer_surface_handle_configure (void *data, struct zwlr_layer_surfac
(void)layer_surface; (void)layer_surface;
zwlr_layer_surface_v1_ack_configure(surface.layer_surface, serial); zwlr_layer_surface_v1_ack_configure(surface.layer_surface, serial);
surface.configured = true; surface.width = width;
surface.height = height;
if ( width != surface_width || height != surface_height ) /* Center neko on first configure. */
fprintf(stderr, "ERROR: Bad dimensions in configure: %d %d\n", width, height); if (!surface.configured)
{
surface.neko_x = (uint16_t)((width / 2) - neko_size);
surface.prev_neko_x = surface.neko_x;
}
surface.configured = true;
surface_next_frame(); surface_next_frame();
} }
@ -723,12 +791,11 @@ static void surface_create (void)
); );
zwlr_layer_surface_v1_set_size( zwlr_layer_surface_v1_set_size(
surface.layer_surface, surface.layer_surface,
surface_width, 0, desired_surface_height
surface_height
); );
zwlr_layer_surface_v1_set_anchor( zwlr_layer_surface_v1_set_anchor(
surface.layer_surface, surface.layer_surface,
ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM | ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT | ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT
); );
/* Empty input region. */ /* Empty input region. */
@ -805,6 +872,25 @@ static void timespec_diff (struct timespec *a, struct timespec *b, struct timesp
} }
} }
static bool colour_from_hex (pixman_color_t *colour, const char *hex)
{
uint16_t r = 0, g = 0, b = 0, a = 255;
if ( 4 != sscanf(hex, "0x%02hx%02hx%02hx%02hx", &r, &g, &b, &a)
&& 3 != sscanf(hex, "0x%02hx%02hx%02hx", &r, &g, &b) )
{
fprintf(stderr, "ERROR: Invalid colour: %s\n", hex);
return false;
}
colour->alpha = (uint16_t)(((double)a / 255.0) * 65535.0);
colour->red = (uint16_t)((((double)r / 255.0) * 65535.0) * colour->alpha / 0xffff);
colour->green = (uint16_t)((((double)g / 255.0) * 65535.0) * colour->alpha / 0xffff);
colour->blue = (uint16_t)((((double)b / 255.0) * 65535.0) * colour->alpha / 0xffff);
return true;
}
int main (void) int main (void)
{ {
init_signals(); init_signals();
@ -812,6 +898,9 @@ int main (void)
wl_list_init(&buffer_pool); wl_list_init(&buffer_pool);
srand((unsigned int)time(0)); srand((unsigned int)time(0));
colour_from_hex(&bg_colour, "0xFFFFFF");
colour_from_hex(&border_colour, "0x000000");
// TODO command line args // TODO command line args
if (!atlas_init()) if (!atlas_init())