powerje / NyanDroid

Ice Cream Nyanwich, bringing ICS to all!
Apache License 2.0
15 stars 2 forks source link

Feature request: adding MooGNU image/music option? #2

Closed bakagirl closed 9 years ago

bakagirl commented 11 years ago

Greetings...I noticed this little program on the FDroid website and couldn't help but wonder if there would be a chance of including the copyleft version of Nyancat dubbed, MooGNU (https://archive.org/details/M00GNU) into the program as another alternative routine or as a easter egg or sorts? License-wise there should be no issues with either the image or the associated music.

Not sure how feasible or hard it would be to implement this, but I thought i'd post the idea anyhow.

powerje commented 11 years ago

Thanks for the input. I haven't had time to work on this in awhile, but the framework is there to support this. If you have time to put it together I'd definitely take a pull request. If you do decide to do this and run into any issues I'd certainly be willing to answer any questions!

Thanks

On Friday, January 11, 2013 at 2:29 AM, Lovejoy wrote:

Greetings...I noticed this little program on the FDroid website and couldn't help but wonder if there would be a chance of including the copyleft version of Nyancat dubbed, MooGNU (https://archive.org/details/M00GNU) into the program as another alternative routine or as a easter egg or sorts? License-wise there should be no issues with either the image or the associated music.
Not sure how feasible or hard it would be to implement this, but I thought i'd post the idea anyhow.

— Reply to this email directly or view it on GitHub (https://github.com/powerje/NyanDroid/issues/2).

bakagirl commented 11 years ago

I'm a bit green in this area i'm afraid, but if I were up to the task I would certainly submit pull request. Nice to hear your framework is open enough to support this kind of idea though! Perhaps someone in the future might take a crack at it.

Previous to MooGNU being accepted into the MATE project one of the people involved started some work on a desktop screensaver similar to your mobile one, but never finished it as far as I can tell. If the code might be any use to you, please feel free to use it. I'm attaching it below since the author has since left github.

Cheers.

/* ============================================================================================ / / This software is created by LAMMJohnson and comes with no warranty of any kind. / / / / 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/LAMMJohnson / / / / 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

include

include

include

ifdef XINERAMA

include <X11/Xlib.h>

include <X11/extensions/Xinerama.h>

endif /_ XINERAMA */

define BUF_SZ 1024

/* Type definitions */ typedef struct { int x, y; } coords;

typedef struct cat_instance cat_instance; struct cat_instance { coords loc; cat_instance *next; };

typedef struct sparkle_instance sparkle_instance; struct sparkle_instance { unsigned int frame, speed; int frame_mov; unsigned int layer; coords loc; sparkle_instance *next; };

/* 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 drawsparkles(void); static void ec_malloc(unsigned int size); static void errout(char _str); static void fillsquare(SDLSurface 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 remove_sparkle(sparkle_instance* s); 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 SDLSurface 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 catinstance cat_list = NULL; 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 sparkle_instance* sparkles_list = NULL; 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;

/* Function definitions _/ static void add_sparkle(void) { sparkleinstance s = sparkles_list; 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;
new->next = NULL;

if (!sparkles_list) {
    sparkles_list = new;
    return;
}

/* Find end of list */
while (s->next)
    s = s->next;
s->next = new;

}

static void add_cat(unsigned int x, unsigned int y) { cat_instance* c = cat_list; cat_instance* new;

new = ec_malloc(sizeof(cat_instance));

new->loc.x = x;
new->loc.y = y;
new->next = NULL;

if (!cat_list) {
    cat_list = new;
    return;
}

/* Find end of list */
while (c->next)
    c = c->next;

c->next = new;

}

static void cleanup(void) { Mix_HaltMusic(); Mix_FreeMusic(music); Mix_CloseAudio(); SDL_Quit(); }

static void clear_screen(void) { sparkle_instance s = sparkles_list; cat_instance c = cat_list;

while (c) {
    /* 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);
    c = c->next;
}

while (s) {
    fillsquare(screen, s->loc.x, s->loc.y, sparkle_img[s->frame]->w, sparkle_img[s->frame]->h, bgcolor);
    s = s->next;
}

}

static void draw_cats(unsigned int frame) { cat_instance* c = cat_list; SDL_Rect pos;

while (c) {
    pos.x = c->loc.x;
    pos.y = c->loc.y;

    if(frame < 2)
        pos.y -= 5;
    SDL_BlitSurface( image_set[frame], NULL, screen, &pos );
    c = c->next;
}

}

static void draw_sparkles() { sparkle_instance* s = sparkles_list; SDL_Rect pos;

while (s) {
    pos.x = s->loc.x;
    pos.y = s->loc.y;
    SDL_BlitSurface( sparkle_img[s->frame], NULL, screen, &pos );
    s = s->next;
}

}

static void ec_malloc(unsigned int size) { void ptr; ptr = malloc(size); if (!ptr) errout("In ec_malloc -- unable to allocate memory."); return ptr; }

static void errout (char *str) { if (str) puts(str); exit(-1); }

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);

}

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 = "basic";

}

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();

}

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());

}

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");

fgets(buffer, BUF_SZ, f);
ANIM_FRAMES_FG = atoi(buffer);
fgets(buffer, BUF_SZ, f);
ANIM_FRAMES_BG = atoi(buffer);

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 remove_sparkle(sparkle_instance* s) { sparkle_instance* s2 = sparkles_list;

if (s2 == s) {
    sparkles_list = s->next;
    free(s);
    return;
}

while (s2->next != s)
    s2 = s2->next;

s2->next = s2->next->next;
free(s);

}

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* next, *s = sparkles_list;

sparkle_spawn_counter += rand() % screen->h;
while(sparkle_spawn_counter >= 1000) {
    add_sparkle();
    sparkle_spawn_counter -= 1000;
}

while(s) {
    s->loc.x -= s->speed;
    next = s->next;

    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)
        remove_sparkle(s);

    s = next;
}

}

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 \"basic\"\n\ (the default) 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; }

powerje commented 9 years ago

Closing due to inactivity. Willing to reopen/accept pull requests if anyone wants to work on this though!