From 976183462c22191a1ef6f91ccd7eae084ffd0a81 Mon Sep 17 00:00:00 2001 From: DiffieHellman Date: Fri, 17 Mar 2023 21:42:26 +1100 Subject: replaced list implementation completely as license is unclear and other improvements --- Makefile | 5 +- dependencies.txt | 6 ++ draw.h | 57 ++++++----- globals.h | 46 +++++---- list.h | 292 ------------------------------------------------------- nyan.c | 105 ++++++++++++++++---- 6 files changed, 155 insertions(+), 356 deletions(-) create mode 100644 dependencies.txt delete mode 100644 list.h diff --git a/Makefile b/Makefile index becb260..db6c669 100644 --- a/Makefile +++ b/Makefile @@ -1,12 +1,11 @@ CC = gcc RES = /usr/share/nyancat BIN = /usr/bin/nyancat -LIBS = -lSDL2 -lSDL2_image -lSDL2_mixer -lm -CFLAGS = -O3 -march=native -flto -Wall +LIBS = -lSDL2 -lSDL2_image -lSDL2_mixer -lm -lX11 -lXrandr +CFLAGS = -O3 -march=native -flto -Wall #-g -fsanitize=address OBJ = nyan.o HEADERS = list.h draw.h globals.h - %.o: %.c $(HEADERS) $(CC) -c -o $@ $< $(CFLAGS) $(LIBS) diff --git a/dependencies.txt b/dependencies.txt new file mode 100644 index 0000000..5bb0db6 --- /dev/null +++ b/dependencies.txt @@ -0,0 +1,6 @@ +x11-libs/libXrandr +x11-libs/libX11 +dev-libs/libbsd +media-libs/libsdl2 +media-libs/sdl2-image USE="png" +media-libs/sdl2-mixer USE="vorbis" diff --git a/draw.h b/draw.h index ab81617..eb14e42 100644 --- a/draw.h +++ b/draw.h @@ -3,45 +3,45 @@ void add_sparkle(void) { - sparkle_instance* new; + sparkle_instance *new = ec_malloc(sizeof(sparkle_instance)); - new = ec_malloc(sizeof(sparkle_instance)); new->loc.x = SCREEN_WIDTH + 80; new->loc.y = (rand() % (SCREEN_HEIGHT + sparkle_height)) - sparkle_height; new->frame = 0; new->frame_mov = 1; new->speed = 10 + (rand() % 30); new->layer = rand() % 2; - list_add(&new->list, &sparkle_list); + + LIST_INSERT_HEAD(&sparkle_list, new, entries); } void add_cat(unsigned int x, unsigned int y) { - cat_instance* new; + cat_instance *new = ec_malloc(sizeof(cat_instance)); - new = ec_malloc(sizeof(cat_instance)); new->loc.x = x; new->loc.y = y; - list_add(&new->list, &cat_list); + + LIST_INSERT_HEAD(&cat_list, new, entries); } void add_rainbow(unsigned int x, unsigned int y) { - rainbow_instance* new; + rainbow_instance *new = ec_malloc(sizeof(rainbow_instance)); - new = ec_malloc(sizeof(rainbow_instance)); new->loc.x = x; new->loc.y = y; new->sprite = rainbow_sprite; - list_add(&new->list, &rainbow_list); + + LIST_INSERT_HEAD(&rainbow_list, new, entries); } void update_rainbows() { cat_instance *c; - /* Rainbows need to be placed according to the cat position (which changes constantly) */ - list_for_each_entry(c, &cat_list, list) + /* rainbows need to be placed according to the cat position (which changes constantly) */ + LIST_FOREACH(c, &cat_list, entries) { add_rainbow((SCREEN_WIDTH - rainbow_width) / 2 - OFFSET /* Default position in the center */ - ((SCREEN_WIDTH - cat_width) / 2 - c->loc.x), /* Plus the amount the cat is off the center */ @@ -50,17 +50,17 @@ void update_rainbows() } - rainbow_instance *r, *tmpr; + rainbow_instance *r, *rtmp; - /* Update the position of each rainbow that exists */ - list_for_each_entry_safe(r, tmpr, &rainbow_list, list) + /* update the position of each rainbow left */ + LIST_FOREACH_SAFE(r, &rainbow_list, entries, rtmp) { r->loc.x -= rainbow_width; - /* If rainbow if off the screen, delete and free() it */ + /* if rainbow is off screen, delete and free() it */ if ((r->loc.x + rainbow_width) < 0) { - list_del(&r->list); + LIST_REMOVE(r, entries); free(r); } } @@ -69,6 +69,7 @@ void update_rainbows() void update_sparkles() { + /* ensure screen has enough sparkles at all times */ sparkle_spawn_counter += rand() % SCREEN_HEIGHT; while (sparkle_spawn_counter >= 1000) { @@ -76,17 +77,20 @@ void update_sparkles() sparkle_spawn_counter -= 1000; } - sparkle_instance *s, *tmps; - list_for_each_entry_safe(s, tmps, &sparkle_list, list) + sparkle_instance *s, *stmp; + LIST_FOREACH_SAFE(s, &sparkle_list, entries, stmp) { + /* move sparkle left */ s->loc.x -= s->speed; s->frame += s->frame_mov; + /* reset sparkle frame */ if (s->frame + 1 >= sparkle_count || s->frame < 1){s->frame_mov = 0 - s->frame_mov;} + /* if sparkle offscreen, delete it */ if ((s->loc.x + sparkle_width) < 0) { - list_del(&s->list); + LIST_REMOVE(s, entries); free(s); } } @@ -96,8 +100,9 @@ void handle_sine() { cat_instance *c; - list_for_each_entry(c, &cat_list, list) + LIST_FOREACH(c, &cat_list, entries) { + /* sine magic */ double pos = (SCREEN_HEIGHT - cat_height)/2 * sin((2*PI*444444)*t); c->loc.y = ((SCREEN_HEIGHT - cat_height)/2 - pos); } @@ -109,9 +114,11 @@ void draw_cats() { cat_instance* c; - list_for_each_entry(c, &cat_list, list) + LIST_FOREACH(c, &cat_list, entries) { + /* source sprite dimensions */ SDL_Rect srcrect = {cat_sprite * cat_width, 0, cat_width, cat_height}; + /* dimensions of destination rectangle */ SDL_Rect dstrect = {c->loc.x, c->loc.y, cat_width*cat_size, cat_height*cat_size}; SDL_RenderCopy(renderer, cat_texture, &srcrect, &dstrect); @@ -122,9 +129,11 @@ void draw_rainbows() { rainbow_instance* r; - list_for_each_entry(r, &rainbow_list, list) + LIST_FOREACH(r, &rainbow_list, entries) { + /* source sprite dimensions */ SDL_Rect srcrect = {r->sprite * rainbow_width, 0, rainbow_width, rainbow_height}; + /* dimensions of destination rectangle */ SDL_Rect dstrect = {r->loc.x, r->loc.y, rainbow_width*cat_size, rainbow_height*cat_size}; SDL_RenderCopy(renderer, rainbow_texture, &srcrect, &dstrect); @@ -135,9 +144,11 @@ void draw_sparkles() { sparkle_instance* s; - list_for_each_entry(s, &sparkle_list, list) + LIST_FOREACH(s, &sparkle_list, entries) { + /* source sprite dimensions */ SDL_Rect srcrect = {sparkle_sprite * sparkle_width, 0, sparkle_width, sparkle_height}; + /* dimensions of destination rectangle */ SDL_Rect dstrect = {s->loc.x, s->loc.y, sparkle_width*cat_size, sparkle_height*cat_size}; SDL_RenderCopy(renderer, sparkle_texture, &srcrect, &dstrect); diff --git a/globals.h b/globals.h index 65b8aaa..b28bf18 100644 --- a/globals.h +++ b/globals.h @@ -3,50 +3,57 @@ #define FRAMERATE 14 #define BUF_SZ 1024 -/* The amount to offset the rainbow off the center of the cat */ +/* the amount to offset the rainbow off the center of the cat */ #define OFFSET 25 #define PI 3.14159265 -/* Type definitions */ +/* type definitions */ typedef struct { int x, y; } coords; -typedef struct cat_instance cat_instance; -struct cat_instance +typedef struct cat cat_instance; +struct cat { coords loc; - struct list_head list; + /* magic to handle the linked list */ + LIST_ENTRY(cat) entries; }; +struct head_cat cat_list; -typedef struct rainbow_instance rainbow_instance; -struct rainbow_instance +typedef struct rainbow rainbow_instance; +struct rainbow { coords loc; unsigned sprite; - struct list_head list; + /* magic to handle the linked list */ + LIST_ENTRY(rainbow) entries; }; +struct head_rainbow rainbow_list; -typedef struct sparkle_instance sparkle_instance; -struct sparkle_instance +typedef struct sparkle sparkle_instance; +struct sparkle { - unsigned int frame, speed; - int frame_mov; - unsigned int layer; + unsigned short frame, speed; + short frame_mov; + unsigned short layer; coords loc; - struct list_head list; + /* magic to handle the linked list */ + LIST_ENTRY(sparkle) entries; }; +struct head_sparkle sparkle_list; SDL_Event event; bool running = true, sound = true, fullscreen = true, cursor = false, sine = false; -int sound_volume = 128, catsize = 0, sparkle_spawn_counter = 0; +int sound_volume = 128, sparkle_spawn_counter = 0; Mix_Music *music; #define BASE_PATH "res" char *cat_dir; -LIST_HEAD(sparkle_list); -LIST_HEAD(cat_list); -LIST_HEAD(rainbow_list); + +LIST_HEAD(head_cat, cat); +LIST_HEAD(head_rainbow, rainbow); +LIST_HEAD(head_sparkle, sparkle); int cat_width, cat_height, rainbow_width, rainbow_height, sparkle_width, sparkle_height; SDL_Renderer *renderer; @@ -54,12 +61,13 @@ SDL_Texture *cat_texture, *rainbow_texture, *sparkle_texture; uint32_t cat_sprite, rainbow_sprite, sparkle_sprite; int cat_count, sparkle_count, rainbow_count; int sparkle_pos; -/* For sine */ +/* for sine */ unsigned t; unsigned cat_num = 1; double cat_size = 1; +/* default screen size for windowed */ unsigned SCREEN_WIDTH = 1200; unsigned SCREEN_HEIGHT = 800; diff --git a/list.h b/list.h deleted file mode 100644 index 233b7de..0000000 --- a/list.h +++ /dev/null @@ -1,292 +0,0 @@ -#ifndef __LIST_H -#define __LIST_H - -/* This file is from the Linux Kernel (include/linux/list.h) - * and modified by simply removing hardware prefetching of list items. - * Copyright, credits attributed to wherever they belong. - * Kulesh Shanmugasundaram (kulesh [squiggly] isis.poly.edu) - * Modified to round out my personal collection by John Anthony - */ - -/* - * Simple doubly linked list implementation. - * - * Some of the internal functions ("__xxx") are useful when - * manipulating whole lists rather than single entries, as - * sometimes we already know the next/prev entries and we can - * generate better code by using them directly rather than - * using the generic single-entry routines. - */ - -#include - -struct list_head { - struct list_head *next; - struct list_head *prev; -}; - -#define LIST_HEAD_INIT(name) { &(name), &(name) } - -#define LIST_HEAD(name) \ - struct list_head name = LIST_HEAD_INIT(name) - -#define INIT_LIST_HEAD(ptr) do { \ - (ptr)->next = (ptr); (ptr)->prev = (ptr); \ -} while (0) - -/* - * Insert a new entry between two known consecutive entries. - * - * This is only for internal list manipulation where we know - * the prev/next entries already! - */ -static inline void -__list_add(struct list_head *new, struct list_head *prev, - struct list_head *next) { - next->prev = new; - new->next = next; - new->prev = prev; - prev->next = new; -} - -/** - * list_add - add a new entry - * @new: new entry to be added - * @head: list head to add it after - * - * Insert a new entry after the specified head. - * This is good for implementing stacks. - */ -static inline void -list_add(struct list_head *new, struct list_head *head) { - __list_add(new, head, head->next); -} - -/** - * list_add_tail - add a new entry - * @new: new entry to be added - * @head: list head to add it before - * - * Insert a new entry before the specified head. - * This is useful for implementing queues. - */ -static inline void -list_add_tail(struct list_head *new, struct list_head *head) { - __list_add(new, head->prev, head); -} - -/* - * Delete a list entry by making the prev/next entries - * point to each other. - * - * This is only for internal list manipulation where we know - * the prev/next entries already! - */ -static inline void -__list_del(struct list_head *prev, struct list_head *next) { - next->prev = prev; - prev->next = next; -} - -/** - * list_del - deletes entry from list. - * @entry: the element to delete from the list. - * Note: list_empty on entry does not return true after this. this - * is undefiend behaviour. - */ -static inline void -list_del(struct list_head *entry) { - __list_del(entry->prev, entry->next); - entry->next = (void *) 0; - entry->prev = (void *) 0; -} - -/** - * list_del_init - deletes entry from list and reinitialize it. - * @entry: the element to delete from the list. - */ -static inline void -list_del_init(struct list_head *entry) { - __list_del(entry->prev, entry->next); - INIT_LIST_HEAD(entry); -} - -/** - * list_move - delete from one list and add as another's head - * @list: the entry to move - * @head: the head that will precede our entry - */ -static inline void -list_move(struct list_head *list, struct list_head *head) { - __list_del(list->prev, list->next); - list_add(list, head); -} - -/** - * list_move_tail - delete from one list and add as another's tail - * @list: the entry to move - * @head: the head that will follow our entry - */ -static inline void -list_move_tail(struct list_head *list, struct list_head *head) { - __list_del(list->prev, list->next); - list_add_tail(list, head); -} - -/** - * list_empty - tests whether a list is empty - * @head: the list to test. - */ -static inline bool -list_empty(struct list_head *head) { - return head->next == head; -} - -static inline void -__list_splice(struct list_head *list, struct list_head *head) { - struct list_head *first = list->next; - struct list_head *last = list->prev; - struct list_head *at = head->next; - - first->prev = head; - head->next = first; - last->next = at; - at->prev = last; -} - -/** - * list_splice - join two lists - * @list: the new list to add. - * @head: the place to add it in the first list. - */ -static inline void -list_splice(struct list_head *list, struct list_head *head) { - if (!list_empty(list)) - __list_splice(list, head); -} - -/** - * list_splice_init - join two lists and reinitialise the emptied list. - * @list: the new list to add. - * @head: the place to add it in the first list. - * - * The list at @list is reinitialised - */ -static inline void -list_splice_init(struct list_head *list, struct list_head *head) { - if (!list_empty(list)) { - __list_splice(list, head); - INIT_LIST_HEAD(list); - } -} - -/** - * list_entry - get the struct for this entry - * @ptr: the &struct list_head pointer. - * @type: the type of the struct this is embedded in. - * @member: the name of the list_struct within the struct. - */ -#define list_entry(ptr, type, member) \ - ((type *)((char *)(ptr)-(unsigned long)(&((type *)0)->member))) - -/** - * list_for_each - iterate over a list - * @pos: the &struct list_head to use as a loop counter. - * @head: the head for your list. - */ -#define list_for_each(pos, head) \ - for (pos = (head)->next; pos != (head); \ - pos = pos->next) -/** - * list_for_each_reverse - iterate over a list backwards - * @pos: the &struct list_head to use as a loop counter. - * @head: the head for your list. - */ -#define list_for_each_reverse(pos, head) \ - for (pos = (head)->prev; pos != (head); \ - pos = pos->prev) - -/** - * list_for_each_safe - iterate over a list safe against removal - * @pos: the &struct list_head to use as a loop counter. - * @n: another &struct list_head to use as temporary storage - * @head: the head for your list. - */ -#define list_for_each_safe(pos, n, head) \ - for (pos = (head)->next, n = pos->next; pos != (head); \ - pos = n, n = pos->next) - -/** - * list_for_each_safe_reverse - iterate list backwards safely - * @pos: the &struct list_head to use as a loop counter. - * @n: another &struct list_head to use as temporary storage - * @head: the head for your list. - */ -#define list_for_each_safe_reverse(pos, n, head) \ - for (pos = (head)->prev, n = pos->prev; pos != (head); \ - pos = n, n = pos->prev) - -/** - * list_for_each_entry - iterate over list of given type - * @pos: the type * to use as a loop counter. - * @head: the head for your list. - * @member: the name of the list_struct within the struct. - */ -#define list_for_each_entry(pos, head, member) \ - for (pos = list_entry((head)->next, typeof(*pos), member); \ - &pos->member != (head); \ - pos = list_entry(pos->member.next, typeof(*pos), member)) - -/** - * list_for_each_entry_reverse - iterate list of given type backwards - * @pos: the type * to use as a loop counter. - * @head: the head for your list. - * @member: the name of the list_struct within the struct. - */ -#define list_for_each_entry_reverse(pos, head, member) \ - for (pos = list_entry((head)->prev, typeof(*pos), member); \ - &pos->member != (head); \ - pos = list_entry(pos->member.prev, typeof(*pos), member)) - -/** - * list_for_each_entry_safe - iterate list entries safe against removal - * @pos: the type * to use as a loop counter. - * @n: another type * to use as temporary storage - * @head: the head for your list. - * @member: the name of the list_struct within the struct. - */ -#define list_for_each_entry_safe(pos, n, head, member) \ - for (pos = list_entry((head)->next, typeof(*pos), member), \ - n = list_entry(pos->member.next, typeof(*pos), member); \ - &pos->member != (head); \ - pos = n, n = list_entry(n->member.next, typeof(*n), member)) - -/** - * list_for_each_entry_safe_reverse - as above but reverse iteration - * @pos: the type * to use as a loop counter. - * @n: another type * to use as temporary storage - * @head: the head for your list. - * @member: the name of the list_struct within the struct. - */ -#define list_for_each_entry_safe_reverse(pos, n, head, member) \ - for (pos = list_entry((head)->prev, typeof(*pos), member), \ - n = list_entry(pos->member.prev, typeof(*pos), member); \ - &pos->member != (head); \ - pos = n, n = list_entry(n->member.prev, typeof(*n), member)) - -/** - * list_len - count number of elements in the given list - * @head: the head for your list - * Note: This is a O(1) time operation and should be used sparingly - */ -static inline size_t -list_len(struct list_head *head) { - struct list_head *iter; - size_t count = 0; - - list_for_each(iter, head) - ++count; - return count; -} - -#endif diff --git a/nyan.c b/nyan.c index 91bcfe3..36b252a 100644 --- a/nyan.c +++ b/nyan.c @@ -4,8 +4,8 @@ /* If you like this software and would like to contribute to its continued improvement */ /* then please feel free to submit bug reports here: www.github.com/JohnAnthony */ /* */ -/* This program is licensed under the GPLv3 and in support of Free and Open Source */ -/* Software in general. The full license can be found at http://www.gnu.org/licenses/gpl.html */ +/* This program is licensed under the GPLv3 and is Free Software */ +/* The full license can be found at http://www.gnu.org/licenses/gpl.html */ /* ============================================================================================ */ #include #include @@ -18,7 +18,10 @@ #include #include #include -#include "list.h" /* Linked list implementation */ +#include // linked list implementation + +#include +#include /* Predecs */ void *ec_malloc(unsigned int size); @@ -32,21 +35,70 @@ void usage(char *exname); #include "globals.h" #include "draw.h" +void get_screen_info() +{ +int iscres, icrtc; + +Display *disp = XOpenDisplay(0); +XRRScreenResources *screen = XRRGetScreenResources(disp, DefaultRootWindow(disp)); +for (iscres = screen->noutput; iscres > 0; ) + { + --iscres; + + XRROutputInfo *info = XRRGetOutputInfo (disp, screen, screen->outputs[iscres]); + if (info->connection == RR_Connected) + { + for (icrtc = info->ncrtc; icrtc > 0;) + { + --icrtc; + + XRRCrtcInfo *crtc_info = XRRGetCrtcInfo (disp, screen, screen->crtcs[icrtc]); + fprintf(stderr, "==> %dx%d+%dx%d\n", crtc_info->x, crtc_info->y, crtc_info->width, crtc_info->height); + + XRRFreeCrtcInfo(crtc_info); + } + } + XRRFreeOutputInfo (info); + } + XRRFreeScreenResources(screen); +} + + + + + + void cleanup(void) { Mix_HaltMusic(); Mix_FreeMusic(music); Mix_CloseAudio(); - /* Free cats */ - cat_instance *c, *tmpc; - list_for_each_entry_safe(c, tmpc, &cat_list, list){list_del(&c->list); free(c);} - /* Free rainbows */ - rainbow_instance *r, *tmpr; - list_for_each_entry_safe(r, tmpr, &rainbow_list, list){list_del(&r->list); free(r);} - /* Free sparkles */ - sparkle_instance *s, *tmps; - list_for_each_entry_safe(s, tmps, &sparkle_list, list){list_del(&s->list); free(s);} + /* free cats */ + cat_instance *c, *ctmp; + LIST_FOREACH_SAFE(c, &cat_list, entries, ctmp) + { + LIST_REMOVE(c, entries); + free(c); + } + + /* free rainbows */ + rainbow_instance *r, *rtmp; + LIST_FOREACH_SAFE(r, &rainbow_list, entries, rtmp) + { + LIST_REMOVE(r, entries); + free(r); + } + + + /* free sparkles */ + sparkle_instance *s, *stmp; + LIST_FOREACH_SAFE(s, &sparkle_list, entries, stmp) + { + LIST_REMOVE(s, entries); + free(s); + } + SDL_DestroyRenderer(renderer); SDL_Quit(); @@ -88,14 +140,15 @@ void handle_args(int argc, char *argv[]) {"data-set", required_argument, 0, 'd'}, {"sine", no_argument, 0, 's'}, {"count", required_argument, 0, 'n'}, + {"version", no_argument, 0, 'V'}, {0, 0, 0, 0} }; /* getopt_long stores the option index here. */ int option_index = 0; - c = getopt_long(argc, argv, "hfwc:abev:r:d:sn:", long_options, &option_index); + c = getopt_long(argc, argv, "hfwc:abev:r:d:sn:V", long_options, &option_index); - /* Detect the end of the options. */ + /* detect the end of the options. */ if (c == -1){break;} switch (c) @@ -169,6 +222,12 @@ void handle_args(int argc, char *argv[]) cat_num = 1; } break; + case 'V': + printf("Copyright (C) 2020 John Antony, 2022 DiffieHellman\n" + "License GPLv3: GNU GPL version 3 \n\n" + "This is free software; you are free to change and redistribute it.\n" + "There is NO WARRANTY, to the extent permitted by law.\n"); + exit(0); case '?': /* getopt_long already printed an error message. */ @@ -236,6 +295,11 @@ void init(void) Mix_VolumeMusic(sound_volume); } + /* init the linked lists */ + LIST_INIT(&cat_list); + LIST_INIT(&rainbow_list); + LIST_INIT(&sparkle_list); + if (cat_num == 1) { add_cat((SCREEN_WIDTH - cat_width) / 2, (SCREEN_HEIGHT - cat_height)/2); @@ -331,7 +395,7 @@ void load_resource_data() rainbow_count = atoi(fgets(buffer, BUF_SZ, fp)); sparkle_count = atoi(fgets(buffer, BUF_SZ, fp)); - if (!cat_count||!rainbow_count||!sparkle_count){errout("Error reading resource data file.");} + if (!cat_count||!rainbow_count||!sparkle_count){errout("Error reading or parsing resource data file.");} fclose(fp); } @@ -349,7 +413,7 @@ void run() { last_draw = SDL_GetTicks(); - /* It's faster to just clear the whole renderer rather than individually overwriting each sprite */ + /* it's faster to just clear the whole renderer rather than individually overwriting each sprite */ SDL_RenderClear(renderer); update_sparkles(); @@ -362,10 +426,10 @@ void run() if (sine){handle_sine();} - /* Display the frame */ + /* display the frame */ SDL_RenderPresent(renderer); - /* Animation sequence increment and looping */ + /* animation sequence increment and looping */ if (++cat_sprite >= cat_count){cat_sprite = 0;} if (++rainbow_sprite >= rainbow_count){rainbow_sprite = 0;} if (++sparkle_sprite >= sparkle_count){sparkle_sprite = 0;} @@ -392,13 +456,16 @@ void usage(char* exname) this program by default are \"default\"\n\ and \"freedom\" sets.\n\ -s, --sine Make cat move in a sine wave.\n\ - -n, --count Number of cats to spawn.\n", exname); + -n, --count Number of cats to spawn.\n\ + -V, --version Version and copyright information.\n", exname); exit(0); } int main(int argc, char *argv[]) { +// get_screen_info(); +// exit(1); handle_args(argc, argv); init(); run(); -- cgit v1.2.3