From c7def3172977a8d128ff9882d67e604e480f3499 Mon Sep 17 00:00:00 2001 From: Gentoo Date: Wed, 6 Jan 2021 21:45:09 +1100 Subject: +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) --- nyan.c | 960 ++++++++++++++++++++++++++--------------------------------------- 1 file changed, 381 insertions(+), 579 deletions(-) (limited to 'nyan.c') 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 -#include -#include +#include +#include +#include #include #include +#include #include #include -#ifdef XINERAMA -#include -#include -#endif /* XINERAMA */ +#include +#include +#include #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, ¤t) != 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: x (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; + } -- cgit v1.2.3