summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGentoo <installgentoo@endianness.com>2021-01-06 21:45:09 +1100
committerGentoo <installgentoo@endianness.com>2021-01-06 21:45:09 +1100
commitc7def3172977a8d128ff9882d67e604e480f3499 (patch)
tree43e0202544ac268462bc6b0ac5228512167a71db
parentba38b130577b92c33a6ef34fec829b38cd647212 (diff)
downloadnyancat-c7def3172977a8d128ff9882d67e604e480f3499.tar.gz
nyancat-c7def3172977a8d128ff9882d67e604e480f3499.tar.bz2
nyancat-c7def3172977a8d128ff9882d67e604e480f3499.zip
+ported to SDL2 +split cat and rainbow draw calls and functions +/- split cat and rainbow images +/- made rainbows drift off screen +spritesheets are now used instead of individual images +"fixed" indentation +replaced old argument code with getopt +added argument that lets you spawn N cats +/- made scaling work (poor results but no longer crashes) +added option to make cat follow sine wave -removed multi screen code (SDL2 fullscreen only works with one screen)
-rw-r--r--Makefile27
-rw-r--r--README35
-rw-r--r--TODO14
-rw-r--r--draw.h147
-rw-r--r--globals.h66
-rw-r--r--list.h4
-rw-r--r--nyan.c960
-rw-r--r--res/default/cat.pngbin0 -> 3183 bytes
-rw-r--r--res/default/data1
-rw-r--r--res/default/nyan.xcfbin0 -> 45424 bytes
-rw-r--r--res/default/rainbow.pngbin0 -> 357 bytes
-rw-r--r--res/default/rainbow.xcfbin0 -> 1020 bytes
-rw-r--r--res/default/sparkle.pngbin0 -> 535 bytes
-rw-r--r--res/default/sparkle.xcfbin0 -> 5162 bytes
-rw-r--r--res/freedom/cat.pngbin0 -> 2030 bytes
-rw-r--r--res/freedom/cat.xcfbin0 -> 40734 bytes
-rw-r--r--res/freedom/data1
-rw-r--r--res/freedom/rainbow.pngbin0 -> 284 bytes
-rw-r--r--res/freedom/rainbow.xcfbin0 -> 4748 bytes
-rw-r--r--res/freedom/sparkle.pngbin0 -> 555 bytes
-rw-r--r--res/freedom/sparkle.xcfbin0 -> 4001 bytes
21 files changed, 627 insertions, 628 deletions
diff --git a/Makefile b/Makefile
index 8abb154..becb260 100644
--- a/Makefile
+++ b/Makefile
@@ -1,24 +1,17 @@
+CC = gcc
RES = /usr/share/nyancat
BIN = /usr/bin/nyancat
-LIBS = -lSDL -lSDL_image -lSDL_mixer -lX11
-FLAGS = -pedantic -Wall -O2 -std=gnu99
-INCS = -I. -I/usr/include ${XINERAMAINC}
+LIBS = -lSDL2 -lSDL2_image -lSDL2_mixer -lm
+CFLAGS = -O3 -march=native -flto -Wall
+OBJ = nyan.o
+HEADERS = list.h draw.h globals.h
-XINERAMAINC = -I/usr/X11R6/include
-XINERAMALIBS = -L/usr/X11R6/lib -lXinerama
-XINERAMAFLAGS = -DXINERAMA
-nyancat: nyan.c list.h
- cc -g nyan.c -o nyancat ${LIBS} ${XINERAMALIBS} ${XINERAMAINC} ${FLAGS} ${XINERAMAFLAGS}
+%.o: %.c $(HEADERS)
+ $(CC) -c -o $@ $< $(CFLAGS) $(LIBS)
-install:
- cp nyancat ${BIN}
- mkdir --parents ${RES}
- cp -rv res/* ${RES}
+nyancat: $(OBJ)
+ $(CC) -o $@ $^ $(CFLAGS) $(LIBS)
clean:
- rm nyancat
-
-uninstall:
- rm ${BIN}
- rm -rv ${RES}
+ rm nyancat $(OBJ)
diff --git a/README b/README
index cb082ba..a8111cf 100644
--- a/README
+++ b/README
@@ -1,21 +1,18 @@
Now with full MooGNU support!
-Usage: nyancat [OPTIONS]
- -h, --help This help message
- -f, --fullscreen Enable fullscreen mode (default)
- -nf, --nofullscreen Disable fullscreen mode
- -c, --catsize Choose size of cat, options are full and
- small. Small is default. "Full" is not
- officially supported.
- -nc, --nocursor Don't show the cursor (default)
- -sc, --cursor, --showcursor Show the cursor
- -ns, --nosound Don't play sound
- -v, --volume Sets Volume, if enabled, from 0 - 128
- -r, --resolution Make next two arguments the screen resolution
- to use (0 and 0 for full resolution)
- (800x600 default)
- -d, --data-set Use an alternate data set. Packaged with
- this program by default are "default" and
- "freedom" sets.
- -hw, -sw Use hardware or software SDL rendering,
- respectively. Hardware is default
+Usage: ./nyancat [OPTIONS]
+ -h, --help This help message.
+ -f, --fullscreen Enable fullscreen (default).
+ -w, --windowed Disable fullscreen.
+ -c, --catsize Choose size to scale cat to (between 0.1 to 10.0)
+ -a, --nocursor Don't show the cursor (default).
+ -b, --cursor Show the cursor.
+ -e, --nosound Don't play sound.
+ -v, --volume Set Volume, if enabled, from 0 - 128.
+ -r, --resolution Argument format: <width>x<height> (1200x800 default).
+ -d, --data-set Use an alternate data set. Packaged with
+ this program by default are "default"
+ and "freedom" sets.
+ -s, --sine Make cat move in a sine wave.
+ -n, --count Number of cats to spawn.
+
diff --git a/TODO b/TODO
index dab926a..be9c899 100644
--- a/TODO
+++ b/TODO
@@ -1,14 +1,6 @@
--- Fix Xinerama support
--- Add more command-line args
+-- Fix multiscreen support
-- Add rc file
-- Add configure script
--- Separate cat and rainbow into separate draw calls (and image files)
-- Add man page(?)
-
--- Fullscreen resolution autodetect broken by most recent update
--> Fixed this temporarily but CPU usage is still proving very high/cat scaling is a bit off for wide monitors
--> Defaulting to the small cat until I can re-implement Xinerama support and fix scaling issues on wide setups
--> -- Johnson
-
--- Increase efficiency of clear_screen() by not blanking the area of sparkles behind a cat
--- Add support for vary long displays ( stretch_cat() function )
+-- Port to xscreensaver(?)
+-- Add more cats
diff --git a/draw.h b/draw.h
new file mode 100644
index 0000000..ab81617
--- /dev/null
+++ b/draw.h
@@ -0,0 +1,147 @@
+#ifndef DRAW_H
+#define DRAW_H
+
+void add_sparkle(void)
+ {
+ sparkle_instance* new;
+
+ 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);
+ }
+
+void add_cat(unsigned int x, unsigned int y)
+ {
+ cat_instance* new;
+
+ new = ec_malloc(sizeof(cat_instance));
+ new->loc.x = x;
+ new->loc.y = y;
+ list_add(&new->list, &cat_list);
+ }
+
+void add_rainbow(unsigned int x, unsigned int y)
+ {
+ rainbow_instance* new;
+
+ new = ec_malloc(sizeof(rainbow_instance));
+ new->loc.x = x;
+ new->loc.y = y;
+ new->sprite = rainbow_sprite;
+ list_add(&new->list, &rainbow_list);
+ }
+
+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)
+ {
+ 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 */
+ (SCREEN_HEIGHT - rainbow_height) / 2 /* Default position in the center */
+ - ((SCREEN_HEIGHT - cat_height) / 2 - c->loc.y));/* Plus the amount the cat is off the center */
+ }
+
+
+ rainbow_instance *r, *tmpr;
+
+ /* Update the position of each rainbow that exists */
+ list_for_each_entry_safe(r, tmpr, &rainbow_list, list)
+ {
+ r->loc.x -= rainbow_width;
+
+ /* If rainbow if off the screen, delete and free() it */
+ if ((r->loc.x + rainbow_width) < 0)
+ {
+ list_del(&r->list);
+ free(r);
+ }
+ }
+ }
+
+void update_sparkles()
+ {
+
+ sparkle_spawn_counter += rand() % SCREEN_HEIGHT;
+ while (sparkle_spawn_counter >= 1000)
+ {
+ add_sparkle();
+ sparkle_spawn_counter -= 1000;
+ }
+
+ sparkle_instance *s, *tmps;
+ list_for_each_entry_safe(s, tmps, &sparkle_list, list)
+ {
+ s->loc.x -= s->speed;
+ s->frame += s->frame_mov;
+
+ if (s->frame + 1 >= sparkle_count || s->frame < 1){s->frame_mov = 0 - s->frame_mov;}
+
+ if ((s->loc.x + sparkle_width) < 0)
+ {
+ list_del(&s->list);
+ free(s);
+ }
+ }
+ }
+
+void handle_sine()
+ {
+ cat_instance *c;
+
+ list_for_each_entry(c, &cat_list, list)
+ {
+ double pos = (SCREEN_HEIGHT - cat_height)/2 * sin((2*PI*444444)*t);
+ c->loc.y = ((SCREEN_HEIGHT - cat_height)/2 - pos);
+ }
+
+ t += 20;
+ }
+
+void draw_cats()
+ {
+ cat_instance* c;
+
+ list_for_each_entry(c, &cat_list, list)
+ {
+ SDL_Rect srcrect = {cat_sprite * cat_width, 0, cat_width, cat_height};
+ SDL_Rect dstrect = {c->loc.x, c->loc.y, cat_width*cat_size, cat_height*cat_size};
+
+ SDL_RenderCopy(renderer, cat_texture, &srcrect, &dstrect);
+ }
+ }
+
+void draw_rainbows()
+ {
+ rainbow_instance* r;
+
+ list_for_each_entry(r, &rainbow_list, list)
+ {
+ SDL_Rect srcrect = {r->sprite * rainbow_width, 0, rainbow_width, rainbow_height};
+ SDL_Rect dstrect = {r->loc.x, r->loc.y, rainbow_width*cat_size, rainbow_height*cat_size};
+
+ SDL_RenderCopy(renderer, rainbow_texture, &srcrect, &dstrect);
+ }
+ }
+
+void draw_sparkles()
+ {
+ sparkle_instance* s;
+
+ list_for_each_entry(s, &sparkle_list, list)
+ {
+ SDL_Rect srcrect = {sparkle_sprite * sparkle_width, 0, sparkle_width, sparkle_height};
+ SDL_Rect dstrect = {s->loc.x, s->loc.y, sparkle_width*cat_size, sparkle_height*cat_size};
+
+ SDL_RenderCopy(renderer, sparkle_texture, &srcrect, &dstrect);
+ }
+ }
+
+#endif
diff --git a/globals.h b/globals.h
new file mode 100644
index 0000000..65b8aaa
--- /dev/null
+++ b/globals.h
@@ -0,0 +1,66 @@
+#ifndef GLOBALS_H
+#define GLOBALS_H
+
+#define FRAMERATE 14
+#define BUF_SZ 1024
+/* The amount to offset the rainbow off the center of the cat */
+#define OFFSET 25
+#define PI 3.14159265
+
+/* Type definitions */
+typedef struct {
+ int x, y;
+} coords;
+
+typedef struct cat_instance cat_instance;
+struct cat_instance
+ {
+ coords loc;
+ struct list_head list;
+ };
+
+typedef struct rainbow_instance rainbow_instance;
+struct rainbow_instance
+ {
+ coords loc;
+ unsigned sprite;
+ struct list_head list;
+ };
+
+typedef struct sparkle_instance sparkle_instance;
+struct sparkle_instance
+ {
+ unsigned int frame, speed;
+ int frame_mov;
+ unsigned int layer;
+ coords loc;
+ struct list_head 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;
+Mix_Music *music;
+
+#define BASE_PATH "res"
+char *cat_dir;
+LIST_HEAD(sparkle_list);
+LIST_HEAD(cat_list);
+LIST_HEAD(rainbow_list);
+
+int cat_width, cat_height, rainbow_width, rainbow_height, sparkle_width, sparkle_height;
+SDL_Renderer *renderer;
+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 */
+unsigned t;
+
+unsigned cat_num = 1;
+double cat_size = 1;
+
+unsigned SCREEN_WIDTH = 1200;
+unsigned SCREEN_HEIGHT = 800;
+
+#endif
diff --git a/list.h b/list.h
index 8d7d0dd..233b7de 100644
--- a/list.h
+++ b/list.h
@@ -1,8 +1,8 @@
#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.
+/* 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
diff --git a/nyan.c b/nyan.c
index 05a71c5..91bcfe3 100644
--- a/nyan.c
+++ b/nyan.c
@@ -7,599 +7,401 @@
/* 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 */
/* ============================================================================================ */
-#include <SDL/SDL.h>
-#include <SDL/SDL_image.h>
-#include <SDL/SDL_mixer.h>
+#include <SDL2/SDL.h>
+#include <SDL2/SDL_image.h>
+#include <SDL2/SDL_mixer.h>
#include <stdio.h>
#include <stdlib.h>
+#include <stdbool.h>
#include <time.h>
#include <string.h>
-#ifdef XINERAMA
-#include <X11/Xlib.h>
-#include <X11/extensions/Xinerama.h>
-#endif /* XINERAMA */
+#include <getopt.h>
+#include <stdint.h>
+#include <math.h>
#include "list.h" /* Linked list implementation */
-#define BUF_SZ 1024
-
-/* Type definitions */
-typedef struct {
- int x, y;
-} coords;
-
-typedef struct cat_instance cat_instance;
-struct cat_instance {
- coords loc;
- struct list_head list;
-};
-
-typedef struct sparkle_instance sparkle_instance;
-struct sparkle_instance {
- unsigned int frame, speed;
- int frame_mov;
- unsigned int layer;
- coords loc;
- struct list_head list;
-};
-
/* Predecs */
-static void add_sparkle(void);
-static void add_cat(unsigned int x, unsigned int y);
-static void cleanup(void);
-static void clear_screen(void);
-static void draw_cats(unsigned int frame);
-static void draw_sparkles(void);
-static void* ec_malloc(unsigned int size);
-static void errout(char *str);
-static void fillsquare(SDL_Surface* surf, int x, int y, int w, int h, Uint32 col);
-static void handle_args(int argc, char** argv);
-static void handle_input(void);
-static void init(void);
-static void load_images(void);
-static SDL_Surface* load_image(const char* path);
-static void load_resource_data(void);
-static void load_music(void);
-static void putpix(SDL_Surface* surf, int x, int y, Uint32 col);
-static void restart_music(void);
-static void run(void);
-static void stretch_images(void);
-static void update_sparkles(void);
-static void usage(char* exname);
-#ifdef XINERAMA
-static void xinerama_add_cats(void);
-#endif /* XINERAMA */
-
-/* Globals */
-static unsigned int FRAMERATE = 14;
-static unsigned int SCREEN_BPP = 32;
-static unsigned int SCREEN_WIDTH = 800;
-static unsigned int SCREEN_HEIGHT = 600;
-static SDL_Surface* screen = NULL;
-static SDL_Event event;
-static int running = 1;
-static int SURF_TYPE = SDL_HWSURFACE;
-static int sound = 1;
-static int sound_volume = 128;
-static int fullscreen = 1;
-static int catsize = 0;
-static int cursor = 0;
-#ifdef XINERAMA
-static Display* dpy;
-#endif /* XINERAMA */
-static int curr_frame = 0;
-static int sparkle_spawn_counter = 0;
-static Mix_Music* music;
-static SDL_Surface** cat_img;
-static SDL_Surface** sparkle_img;
-static SDL_Surface** stretch_cat;
-static SDL_Surface** image_set;
-static Uint32 bgcolor;
-static char* RESOURCE_PATH = NULL;
-static char* LOC_BASE_PATH = "res";
-static char* OS_BASE_PATH = "/usr/share/nyancat";
-static int ANIM_FRAMES_FG = 0;
-static int ANIM_FRAMES_BG = 0;
-static LIST_HEAD(sparkle_list);
-static LIST_HEAD(cat_list);
-
-/* Function definitions */
-static void
-add_sparkle(void) {
- sparkle_instance* new;
-
- new = ec_malloc(sizeof(sparkle_instance));
- new->loc.x = screen->w + 80;
- new->loc.y = (rand() % (screen->h + sparkle_img[0]->h)) - sparkle_img[0]->h;
- new->frame = 0;
- new->frame_mov = 1;
- new->speed = 10 + (rand() % 30);
- new->layer = rand() % 2;
- list_add(&new->list, &sparkle_list);
-}
-
-static void
-add_cat(unsigned int x, unsigned int y) {
- cat_instance* new;
-
- new = ec_malloc(sizeof(cat_instance));
- new->loc.x = x;
- new->loc.y = y;
- list_add(&new->list, &cat_list);
-}
-
-static void
-cleanup(void) {
- Mix_HaltMusic();
- Mix_FreeMusic(music);
- Mix_CloseAudio();
- SDL_Quit();
-}
-
-static void
-clear_screen(void) {
- sparkle_instance *s;
- cat_instance *c;
-
- list_for_each_entry(c, &cat_list, list) {
- /* This is bad. These magic numbers are to make up for uneven image sizes */
- fillsquare(screen,
- c->loc.x,
- c->loc.y - (curr_frame < 2 ? 0 : 5),
- image_set[curr_frame]->w + 6,
- image_set[curr_frame]->h + 5,
- bgcolor);
- }
-
- list_for_each_entry(s, &sparkle_list, list) {
- fillsquare(screen,
- s->loc.x,
- s->loc.y,
- sparkle_img[s->frame]->w,
- sparkle_img[s->frame]->h,
- bgcolor);
- }
-
-}
-
-static void
-draw_cats(unsigned int frame) {
- cat_instance* c;
- SDL_Rect pos;
-
- list_for_each_entry(c, &cat_list, list) {
- pos.x = c->loc.x;
- pos.y = c->loc.y;
-
- if(frame < 2)
- pos.y -= 5;
- SDL_BlitSurface( image_set[frame], NULL, screen, &pos );
- }
+void *ec_malloc(unsigned int size);
+void errout(char *str);
+void load_images();
+void load_resource_data();
+void load_music();
+void restart_music();
+void usage(char *exname);
+
+#include "globals.h"
+#include "draw.h"
+
+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);}
+
+ SDL_DestroyRenderer(renderer);
+ SDL_Quit();
+ }
+
+void *ec_malloc(unsigned int size)
+ {
+ void *ptr = malloc(size);
+ if (!ptr){errout("In ec_malloc -- unable to allocate memory.");}
+
+ return ptr;
+ }
+
+void errout(char *str)
+ {
+ if (str){fprintf(stderr,"%s\n",str);}
+ exit(1);
+ }
+
+
+void handle_args(int argc, char *argv[])
+ {
+ int c, volume;
+ char *x; //position of x in resolution (e.g. 800x600)
+
+ while(1)
+ {
+ static struct option long_options[] =
+ {
+ {"help", no_argument, 0, 'h'},
+ {"fullscreen", no_argument, 0, 'f'},
+ {"windowed", no_argument, 0, 'w'},
+ {"catsize", required_argument, 0, 'c'},
+ {"nocursor", no_argument, 0, 'a'},
+ {"cursor", no_argument, 0, 'b'},
+ {"nosound", no_argument, 0, 'e'},
+ {"volume", required_argument, 0, 'v'},
+ {"resolution", required_argument, 0, 'r'},
+ {"data-set", required_argument, 0, 'd'},
+ {"sine", no_argument, 0, 's'},
+ {"count", required_argument, 0, 'n'},
+ {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);
+
+ /* Detect the end of the options. */
+ if (c == -1){break;}
+
+ switch (c)
+ {
+ case 'h':
+ usage(argv[0]);
+ break;
+ case 'f':
+ fullscreen = true;
+ break;
+ case 'w':
+ fullscreen = false;
+ break;
+ case 'c':
+ cat_size = atof(optarg);
+ if (cat_size < 0.1 || cat_size > 10)
+ {
+ fprintf(stderr,"Size of cat is invalid, set to default.\n");
+ cat_size = 1;
+ }
+ break;
+ case 'a':
+ cursor = false;
+ break;
+ case 'b':
+ cursor = true;
+ break;
+ case 'e':
+ sound = false;
+ break;
+ case 'v':
+ volume = atoi(optarg);
+ if(volume >= 0 && volume <= 128){sound_volume = volume;}
+ else
+ {
+ fprintf(stderr,"Arguments for Volume are not valid. Disabling sound.\n");
+ sound = false;
+ }
+ break;
+
+ case 'r':
+ x = strchr(optarg,'x');
+ if (!x){fprintf(stderr,"Argument for resolution is invalid, resolution set to default.\n"); break;}
+ *x = '\0';
+
+ if (*(x+1) == '\0'){fprintf(stderr,"Argument for resolution is invalid, resolution set to default.\n"); break;}
+
+ int dims[2] = {atoi(optarg), atoi(x+1)};
+ if (dims[0] >= 0 && dims[0] < 10000 && dims[1] >= 0 && dims[1] < 5000)
+ {
+ SCREEN_WIDTH = dims[0];
+ SCREEN_HEIGHT = dims[1];
+ }
+ else {fprintf(stderr,"Argument for resolution is invalid, resolution set to default.\n");}
+ break;
+
+ case 'd':
+ if (cat_dir){free(cat_dir);}
+ cat_dir = strdup(optarg);
+ break;
+
+ case 's':
+ sine = true;
+ break;
+
+ case 'n':
+ cat_num = atoi(optarg);
+ if (cat_num <= 0 || cat_num > 10000)
+ {
+ fprintf(stderr,"Number of cats are invalid, set to 1.\n");
+ cat_num = 1;
+ }
+ break;
+
+ case '?':
+ /* getopt_long already printed an error message. */
+ break;
+
+ default:
+ exit(1);
+ }
+ }
+ if (!cat_dir){cat_dir = "default";}
}
-static void
-draw_sparkles() {
- sparkle_instance* s;
- SDL_Rect pos;
+void handle_input(void)
+ {
+ while(SDL_PollEvent(&event))
+ {
+ switch (event.type)
+ {
+ case SDL_KEYDOWN:
+ case SDL_QUIT:
+ running = false;
+ break;
+ }
+ }
+ }
+
+void init(void)
+ {
+ srand(time(NULL));
+
+ SDL_Init(SDL_INIT_VIDEO|SDL_INIT_AUDIO|IMG_INIT_PNG);
+
+ SDL_Window *window;
+ if (fullscreen)
+ {
+ window = SDL_CreateWindow("Nyan cat", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, 0, 0, SDL_WINDOW_FULLSCREEN_DESKTOP);
+ /* Set screen width and height to fullscreen resolution*/
+ SDL_DisplayMode current;
+ if (SDL_GetCurrentDisplayMode(0, &current) != 0){errout("SDL could not get display mode for screen");}
+ SCREEN_WIDTH = current.w;
+ SCREEN_HEIGHT = current.h;
+ }
+
+ else {window = SDL_CreateWindow("Nyan cat", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, SCREEN_WIDTH, SCREEN_HEIGHT, SDL_WINDOW_MAXIMIZED);}
+ if (!cursor){SDL_ShowCursor(0);}
+
+ renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC);
+
+ load_images();
+ load_resource_data();
+
+ /* Divide the *_width by *_count, so we don't need to calculate width/count every time */
+ cat_width /= cat_count;
+ rainbow_width /= rainbow_count;
+ sparkle_width /= sparkle_count;
+
+ SDL_SetRenderDrawColor(renderer, 0x00, 0x33, 0x66, 255);
+ SDL_RenderClear(renderer);
+
+ if (sound)
+ {
+ Mix_OpenAudio(44100, AUDIO_S16, 2, 256);
+ load_music();
+ Mix_PlayMusic(music, 0);
+ Mix_VolumeMusic(sound_volume);
+ }
+
+ if (cat_num == 1)
+ {
+ add_cat((SCREEN_WIDTH - cat_width) / 2, (SCREEN_HEIGHT - cat_height)/2);
+ add_rainbow((SCREEN_WIDTH - rainbow_width) / 2 - OFFSET, (SCREEN_HEIGHT - rainbow_height) / 2);
+ }
+ else
+ {
+ for (int i = 0; i < cat_num; ++i)
+ {
+ unsigned x = rand() % (SCREEN_WIDTH - cat_width);
+ unsigned y = rand() % (SCREEN_HEIGHT - cat_height);
+ add_cat(x,y);
+ add_rainbow(x - OFFSET, y);
+ }
+ }
+
+
+ /* clear initial input */
+ while(SDL_PollEvent(&event));
+
+ /* Pre-populate with sparkles */
+ for (int i = 0; i < 200; ++i){update_sparkles();}
- list_for_each_entry(s, &sparkle_list, list) {
- pos.x = s->loc.x;
- pos.y = s->loc.y;
- SDL_BlitSurface( sparkle_img[s->frame], NULL, screen, &pos );
- }
}
-static void*
-ec_malloc(unsigned int size) {
- void *ptr;
- ptr = malloc(size);
- if (!ptr)
- errout("In ec_malloc -- unable to allocate memory.");
- return ptr;
-}
+SDL_Surface* load_image(const char* path)
+ {
+ SDL_Surface* loadedImage = NULL;
+ SDL_Surface* optimizedImage = NULL;
-static void
-errout (char *str) {
- if (str)
- puts(str);
- exit(-1);
-}
+ loadedImage = IMG_Load(path);
+ if(loadedImage)
+ {
+ SDL_PixelFormat *format = SDL_AllocFormat(SDL_PIXELFORMAT_RGBA32);
+ optimizedImage = SDL_ConvertSurface(loadedImage, format, 0);
+ SDL_FreeSurface(loadedImage);
+ }
-static void
-fillsquare(SDL_Surface* surf, int x, int y, int w, int h, Uint32 col) {
- int i, e;
-
- if (x + w < 0 || y + h < 0 || x > surf->w || y > surf->h)
- return;
-
- /* Sanitising of inputs. Make sure we're not drawing off of the surface */
- if (x + w > surf->w)
- w = surf->w - x;
- if (y + h > surf->h)
- h = surf->h - y;
- if (x < 0) {
- w += x;
- x = 0;
- }
- if (y < 0) {
- h += y;
- y = 0;
- }
-
- for (i = x; i < x + w; i++)
- for (e = y; e < y + h; e++)
- putpix(surf, i, e, col);
-}
+ return optimizedImage;
+ }
-static void
-handle_args(int argc, char **argv) {
- int i;
-
- /* This REALLY needs to be replaced with getopt */
-
- for (i = 1; i < argc; i++) {
- if (!strcmp(argv[i], "-hw"))
- SURF_TYPE = SDL_HWSURFACE;
- else if (!strcmp(argv[i], "-sw"))
- SURF_TYPE = SDL_SWSURFACE;
- else if (!strcmp(argv[i], "-f") || !strcmp(argv[i], "--fullscreen"))
- fullscreen = 1;
- else if(!(strcmp(argv[i], "-nf") || !strcmp(argv[i], "--nofullscreen")))
- fullscreen = 0;
- else if(!strcmp(argv[i], "-nc") || !strcmp(argv[i], "--nocursor"))
- cursor = 0;
- else if(!strcmp(argv[i], "-sc") || !strcmp(argv[i], "--cursor") || !strcmp(argv[i], "--showcursor"))
- cursor = 1;
- else if(!strcmp(argv[i], "-ns") || !strcmp(argv[i], "--nosound"))
- sound = 0;
- else if((!strcmp(argv[i], "-v") || !strcmp(argv[i], "--volume")) && i < argc - 1) {
- int vol = atoi(argv[++i]);
- if(vol >= 0 && vol <= 128){
- sound_volume = vol;
- }
- else {
- puts("Arguments for Volume are not valid. Disabling sound.");
- sound = 0;
- }
- }
- else if(!strcmp(argv[i], "-h") || !strcmp(argv[i], "--help"))
- usage(argv[0]);
- else if(!strcmp(argv[i], "-c") || !strcmp(argv[i], "--catsize")) {
- if (++i < argc) {
- if(!strcmp(argv[i], "full"))
- catsize = 1;
- else if(!strcmp(argv[i], "small"))
- catsize = 0;
- else
- printf("Unrecognised scaling option: %s - please select either 'full' or 'small' cat size.\n", argv[i]);
- }
- }
- else if(!strcmp(argv[i], "-d") || !strcmp(argv[i], "--data-set")) {
- if (++i < argc) {
- if (RESOURCE_PATH)
- free(RESOURCE_PATH);
- RESOURCE_PATH = strdup(argv[i]);
- }
- }
- else if((!strcmp(argv[i], "-r") && strcmp(argv[i], "--resolution")) && i < argc - 2) {
- int dims[2] = { atoi(argv[++i]), atoi(argv[++i]) };
- if (dims[0] >= 0 && dims[0] < 10000 && dims[1] >= 0 && dims[1] < 5000) { // Borrowed from PixelUnsticker, changed the variable name
- SCREEN_WIDTH = dims[0];
- SCREEN_HEIGHT = dims[1];
- }
- else
- puts("Arguments do not appear to be valid screen sizes. Defaulting.");
- }
- else
- printf("Unrecognised option: %s\n", argv[i]);
- }
-
- if (!RESOURCE_PATH)
- RESOURCE_PATH = "default";
-}
+void load_images()
+ {
+ char buffer[BUF_SZ];
+ SDL_Surface *cat_img, *rainbow_img, *sparkle_img;
-static void
-handle_input(void) {
- while( SDL_PollEvent( &event ) ) {
- switch (event.type) {
- case SDL_KEYDOWN:
- case SDL_QUIT:
- case SDL_MOUSEMOTION:
- running = 0;
- break;
- }
- }
-}
-
-static void
-init(void) {
- int i;
-
- srand( time(NULL) );
-
- SDL_Init( SDL_INIT_EVERYTHING );
- if (fullscreen)
- screen = SDL_SetVideoMode( 0, 0, SCREEN_BPP, SURF_TYPE | SDL_FULLSCREEN );
- else
- screen = SDL_SetVideoMode( SCREEN_WIDTH, SCREEN_HEIGHT, SCREEN_BPP, SURF_TYPE );
- if(!cursor)
- SDL_ShowCursor(0);
-
- load_resource_data();
- load_images();
- bgcolor = SDL_MapRGB(screen->format, 0x00, 0x33, 0x66);
- fillsquare(screen, 0, 0, screen->w, screen->h, bgcolor);
-
- if(sound) {
- Mix_OpenAudio( 44100, AUDIO_S16, 2, 256 );
- load_music();
- Mix_PlayMusic(music, 0);
- Mix_VolumeMusic(sound_volume);
- }
-
- /* Choose our image set */
- if (catsize == 1)
- image_set = stretch_cat;
- else
- image_set = cat_img;
-
-/* Ugly */
-#ifdef XINERAMA
- if (!(dpy = XOpenDisplay(NULL)))
- puts("Failed to open Xinerama display information.");
- else{
- if(catsize == 1)
- stretch_images();
- xinerama_add_cats();
- XCloseDisplay(dpy);
- }
-#else
- if(catsize == 1)
- add_cat(0, (screen->h - image_set[0]->h) / 2);
- else {
- add_cat((screen->w - cat_img[0]->w) / 2, (screen->h - cat_img[0]->h) / 2);
- }
-#endif /* Xinerama */
-
- /* clear initial input */
- while( SDL_PollEvent( &event ) ) {}
-
- /* Pre-populate with sparkles */
- for (i = 0; i < 200; i++)
- update_sparkles();
-}
+ /* Load images */
+ snprintf(buffer, BUF_SZ, "%s/%s/cat.png", BASE_PATH, cat_dir);
+ cat_img = load_image(buffer);
-static void
-load_images(void) {
- int i;
- char buffer[BUF_SZ];
-
- cat_img = ec_malloc(sizeof(SDL_Surface*) * ANIM_FRAMES_FG);
- sparkle_img = ec_malloc(sizeof(SDL_Surface*) * ANIM_FRAMES_BG);
-
- /* Loading logic */
- for (i = 0; i < ANIM_FRAMES_FG; ++i) {
- snprintf(buffer, BUF_SZ, "%s/%s/fg%02d.png", LOC_BASE_PATH, RESOURCE_PATH, i);
- cat_img[i] = load_image(buffer);
- if (!cat_img[i]) {
- snprintf(buffer, BUF_SZ, "%s/%s/fg%02d.png", OS_BASE_PATH, RESOURCE_PATH, i);
- cat_img[i] = load_image(buffer);
- }
- }
- for (i = 0; i < ANIM_FRAMES_BG; ++i) {
- snprintf(buffer, BUF_SZ, "%s/%s/bg%02d.png", LOC_BASE_PATH, RESOURCE_PATH, i);
- sparkle_img[i] = load_image(buffer);
- if (!sparkle_img[i]) {
- snprintf(buffer, BUF_SZ, "%s/%s/bg%02d.png", OS_BASE_PATH, RESOURCE_PATH, i);
- sparkle_img[i] = load_image(buffer);
- }
- }
-
- /* Check everything loaded properly */
- for (int i = 0; i < ANIM_FRAMES_FG; ++i)
- if (!cat_img[i])
- errout("Error loading foreground images.");
-
- for (int i = 0; i < ANIM_FRAMES_BG; ++i)
- if (!sparkle_img[i])
- errout("Error loading background images.");
-}
-
-static SDL_Surface*
-load_image( const char* path ) {
- SDL_Surface* loadedImage = NULL;
- SDL_Surface* optimizedImage = NULL;
-
- loadedImage = IMG_Load( path );
- if(loadedImage) {
- optimizedImage = SDL_DisplayFormatAlpha( loadedImage );
- SDL_FreeSurface( loadedImage );
- }
- return optimizedImage;
-}
-
-static void
-load_music(void) {
- char buffer[BUF_SZ];
-
- snprintf(buffer, BUF_SZ, "%s/%s/music.ogg", LOC_BASE_PATH, RESOURCE_PATH);
- music = Mix_LoadMUS(buffer);
- if (!music) {
- snprintf(buffer, BUF_SZ, "%s/%s/music.ogg", OS_BASE_PATH, RESOURCE_PATH);
- music = Mix_LoadMUS(buffer);
- }
- if (!music)
- printf("Unable to load Ogg file: %s\n", Mix_GetError());
- else
- Mix_HookMusicFinished(restart_music);
-}
-
-static void
-load_resource_data(void) {
- FILE *f;
- char buffer[BUF_SZ];
-
- snprintf(buffer, BUF_SZ, "%s/%s/data", LOC_BASE_PATH, RESOURCE_PATH);
- f = fopen(buffer, "r");
- if (!f) {
- snprintf(buffer, BUF_SZ, "%s/%s/data", OS_BASE_PATH, RESOURCE_PATH);
- f = fopen(buffer, "r");
- }
- if (!f)
- errout("Error opening resource data file");
-
- ANIM_FRAMES_FG = atoi(fgets(buffer, BUF_SZ, f));
- ANIM_FRAMES_BG = atoi(fgets(buffer, BUF_SZ, f));
-
- if (!ANIM_FRAMES_FG || !ANIM_FRAMES_BG)
- errout("Error reading resource data file.");
-}
-
-static void
-putpix(SDL_Surface* surf, int x, int y, Uint32 col) {
- Uint32 *pix = (Uint32 *) surf->pixels;
- pix [ ( y * surf->w ) + x ] = col;
-}
-
-static void
-restart_music(void) {
- Mix_PlayMusic(music, 0);
-}
-
-static void
-run(void) {
- unsigned int last_draw, draw_time;
-
- while( running ) {
- last_draw = SDL_GetTicks();
-
- clear_screen();
- update_sparkles();
- draw_sparkles();
- draw_cats(curr_frame);
-
- handle_input();
- SDL_Flip(screen);
-
- /* Frame increment and looping */
- curr_frame++;
- if (curr_frame >= ANIM_FRAMES_FG)
- curr_frame = 0;
-
- draw_time = SDL_GetTicks() - last_draw;
- if (draw_time < (1000 / FRAMERATE))
- SDL_Delay((1000 / FRAMERATE) - draw_time);
- }
-}
-
-static void
-stretch_images(void) {
- SDL_Rect stretchto;
- stretchto.w = 0;
- stretchto.h = 0;
-
- /* Just use the x co-ordinate for scaling for now. This does, however,
- need to be changed to accomodate taller resolutions */
-#ifdef XINERAMA
- int i, nn;
- XineramaScreenInfo* info = XineramaQueryScreens(dpy, &nn);
-
- for (i = 0; i < nn; ++i) {
- if(!stretchto.w || info[i].width < stretchto.w)
- stretchto.w = info[i].width;
- }
-
- XFree(info);
-#endif /* XINERAMA */
- if (!stretchto.w)
- stretchto.w = screen->w;
-
- /* Handle a slight scaling down */
- stretchto.w *= 0.9;
- stretchto.h = stretchto.w * cat_img[0]->h / cat_img[0]->w;
-
- SDL_PixelFormat fmt = *(cat_img[0]->format);
- for (int i=0; i <= ANIM_FRAMES_FG; i++) {
- stretch_cat[i] = SDL_CreateRGBSurface(SURF_TYPE, stretchto.w,
- stretchto.h,SCREEN_BPP,fmt.Rmask,fmt.Gmask,fmt.Bmask,fmt.Amask);
- SDL_SoftStretch(cat_img[i],NULL,stretch_cat[i],NULL);
- }
-
-}
-
-static void
-update_sparkles(void) {
- sparkle_instance *s;
- sparkle_instance *tmp;
-
- sparkle_spawn_counter += rand() % screen->h;
- while(sparkle_spawn_counter >= 1000) {
- add_sparkle();
- sparkle_spawn_counter -= 1000;
- }
-
- list_for_each_entry_safe(s, tmp, &sparkle_list, list) {
- s->loc.x -= s->speed;
- s->frame += s->frame_mov;
-
- if(s->frame + 1 >= ANIM_FRAMES_BG || s->frame < 1)
- s->frame_mov = 0 - s->frame_mov;
-
- if (s->loc.x < 0 - sparkle_img[0]->w) {
- list_del(&s->list);
- free(s);
- }
- }
-}
-
-static void
-usage(char* exname) {
- printf("Usage: %s [OPTIONS]\n\
- -h, --help This help message\n\
- -f, --fullscreen Enable fullscreen mode (default)\n\
- -nf, --nofullscreen Disable fullscreen mode\n\
- -c, --catsize Choose size of cat, options are full and \n\
- small. Small is default. \"Full\" not\n\
- officially supported.\n\
- -nc, --nocursor Don't show the cursor (default)\n\
- -sc, --cursor, --showcursor Show the cursor\n\
- -ns, --nosound Don't play sound\n\
- -v, --volume Set Volume, if enabled, from 0 - 128\n\
- -r, --resolution Make next two arguments the screen \n\
- resolution to use (0 and 0 for full \n\
- resolution) (800x600 default)\n\
- -d, --data-set Use an alternate data set. Packaged with\n\
- this program by default are \"default\"\n\
- and \"freedom\" sets.\n\
- -hw, -sw Use hardware or software SDL rendering, \n\
- respectively. Hardware is default\n", exname);
- exit(0);
-}
-
-#ifdef XINERAMA
-static void
-xinerama_add_cats(void) {
- int i, nn;
- XineramaScreenInfo* info = XineramaQueryScreens(dpy, &nn);
-
- for (i = 0; i < nn; ++i) {
- if(fullscreen) {
- add_cat(info[i].x_org + ((info[i].width - image_set[0]->w) / 2),
- info[i].y_org + ((info[i].height - image_set[0]->h) / 2));
- }
- else {
- add_cat((SCREEN_WIDTH - image_set[0]->w) / 2,
- (SCREEN_HEIGHT - image_set[0]->h) / 2);
- }
- }
-
- XFree(info);
-}
-#endif /* XINERAMA */
-
-int main( int argc, char **argv ) {
- handle_args(argc, argv);
- init();
- run();
- cleanup();
- return 0;
-}
+ snprintf(buffer, BUF_SZ, "%s/%s/rainbow.png", BASE_PATH, cat_dir);
+ rainbow_img = load_image(buffer);
+
+
+ snprintf(buffer, BUF_SZ, "%s/%s/sparkle.png", BASE_PATH, cat_dir);
+ sparkle_img = load_image(buffer);
+
+ /* Check everything loaded properly */
+ if (!cat_img||!rainbow_img||!sparkle_img){errout("Error loading images.");}
+
+ /* Create textures from images */
+ cat_texture = SDL_CreateTextureFromSurface(renderer, cat_img);
+ rainbow_texture = SDL_CreateTextureFromSurface(renderer, rainbow_img);
+ sparkle_texture = SDL_CreateTextureFromSurface(renderer, sparkle_img);
+
+ /* Get width and height from all the textures */
+ SDL_QueryTexture(cat_texture, NULL, NULL, &cat_width, &cat_height);
+ SDL_QueryTexture(rainbow_texture, NULL, NULL, &rainbow_width, &rainbow_height);
+ SDL_QueryTexture(sparkle_texture, NULL, NULL, &sparkle_width, &sparkle_height);
+ }
+
+void load_music()
+ {
+ char buffer[BUF_SZ];
+
+ snprintf(buffer, BUF_SZ, "%s/%s/music.ogg", BASE_PATH, cat_dir);
+ music = Mix_LoadMUS(buffer);
+
+ if (!music){fprintf(stderr,"Unable to load Ogg file: %s\n", Mix_GetError());}
+ else {Mix_HookMusicFinished(restart_music);}
+ }
+
+void load_resource_data()
+ {
+ char buffer[BUF_SZ];
+
+ snprintf(buffer, BUF_SZ, "%s/%s/data", BASE_PATH, cat_dir);
+ FILE *fp = fopen(buffer, "r");
+
+ if (!fp){errout("Error opening resource data file");}
+
+ cat_count = atoi(fgets(buffer, BUF_SZ, fp));
+ 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.");}
+
+ fclose(fp);
+ }
+
+void restart_music()
+ {
+ Mix_PlayMusic(music, 0);
+ }
+
+void run()
+ {
+ unsigned int last_draw, draw_time;
+
+ while(running)
+ {
+ last_draw = SDL_GetTicks();
+
+ /* It's faster to just clear the whole renderer rather than individually overwriting each sprite */
+ SDL_RenderClear(renderer);
+
+ update_sparkles();
+ update_rainbows();
+ draw_sparkles();
+ draw_rainbows();
+ draw_cats();
+
+ handle_input();
+
+ if (sine){handle_sine();}
+
+ /* Display the frame */
+ SDL_RenderPresent(renderer);
+
+ /* 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;}
+
+ /* Avoid wasting CPU & GPU by only drawing at the framerate */
+ draw_time = SDL_GetTicks() - last_draw;
+ if (draw_time < (1000 / FRAMERATE)){SDL_Delay((1000 / FRAMERATE) - draw_time);}
+ }
+ }
+
+void usage(char* exname)
+ {
+ fprintf(stderr,"Usage: %s [OPTIONS]\n\
+ -h, --help This help message.\n\
+ -f, --fullscreen Enable fullscreen (default).\n\
+ -w, --windowed Disable fullscreen.\n\
+ -c, --catsize Choose size to scale cat to (between 0.1 to 10.0)\n\
+ -a, --nocursor Don't show the cursor (default).\n\
+ -b, --cursor Show the cursor.\n\
+ -e, --nosound Don't play sound.\n\
+ -v, --volume Set Volume, if enabled, from 0 - 128.\n\
+ -r, --resolution Argument format: <width>x<height> (1200x800 default).\n\
+ -d, --data-set Use an alternate data set. Packaged with\n\
+ 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);
+
+ exit(0);
+ }
+
+int main(int argc, char *argv[])
+ {
+ handle_args(argc, argv);
+ init();
+ run();
+ cleanup();
+ return 0;
+ }
diff --git a/res/default/cat.png b/res/default/cat.png
new file mode 100644
index 0000000..5d61f67
--- /dev/null
+++ b/res/default/cat.png
Binary files differ
diff --git a/res/default/data b/res/default/data
index fd3c81a..63fd91f 100644
--- a/res/default/data
+++ b/res/default/data
@@ -1,2 +1,3 @@
5
+2
5
diff --git a/res/default/nyan.xcf b/res/default/nyan.xcf
new file mode 100644
index 0000000..6addb48
--- /dev/null
+++ b/res/default/nyan.xcf
Binary files differ
diff --git a/res/default/rainbow.png b/res/default/rainbow.png
new file mode 100644
index 0000000..2866ff2
--- /dev/null
+++ b/res/default/rainbow.png
Binary files differ
diff --git a/res/default/rainbow.xcf b/res/default/rainbow.xcf
new file mode 100644
index 0000000..1b0ea7a
--- /dev/null
+++ b/res/default/rainbow.xcf
Binary files differ
diff --git a/res/default/sparkle.png b/res/default/sparkle.png
new file mode 100644
index 0000000..a2cb2ac
--- /dev/null
+++ b/res/default/sparkle.png
Binary files differ
diff --git a/res/default/sparkle.xcf b/res/default/sparkle.xcf
new file mode 100644
index 0000000..51ec74e
--- /dev/null
+++ b/res/default/sparkle.xcf
Binary files differ
diff --git a/res/freedom/cat.png b/res/freedom/cat.png
new file mode 100644
index 0000000..da75800
--- /dev/null
+++ b/res/freedom/cat.png
Binary files differ
diff --git a/res/freedom/cat.xcf b/res/freedom/cat.xcf
new file mode 100644
index 0000000..d4ccc3d
--- /dev/null
+++ b/res/freedom/cat.xcf
Binary files differ
diff --git a/res/freedom/data b/res/freedom/data
index 7290ba8..c46162e 100644
--- a/res/freedom/data
+++ b/res/freedom/data
@@ -1,2 +1,3 @@
4
+2
4
diff --git a/res/freedom/rainbow.png b/res/freedom/rainbow.png
new file mode 100644
index 0000000..58f1591
--- /dev/null
+++ b/res/freedom/rainbow.png
Binary files differ
diff --git a/res/freedom/rainbow.xcf b/res/freedom/rainbow.xcf
new file mode 100644
index 0000000..34a751f
--- /dev/null
+++ b/res/freedom/rainbow.xcf
Binary files differ
diff --git a/res/freedom/sparkle.png b/res/freedom/sparkle.png
new file mode 100644
index 0000000..3ba85df
--- /dev/null
+++ b/res/freedom/sparkle.png
Binary files differ
diff --git a/res/freedom/sparkle.xcf b/res/freedom/sparkle.xcf
new file mode 100644
index 0000000..b4ead3c
--- /dev/null
+++ b/res/freedom/sparkle.xcf
Binary files differ