/******************************************************************************* * * Copyright (c) 2001, 2002 Guillaume Cottenceau (guillaume.cottenceau at free.fr) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2, as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ******************************************************************************/ #include "EXTERN.h" #include "perl.h" #include "XSUB.h" #include #ifdef MACOSX #include #else #include #endif const int XRES = 640; const int YRES = 480; int x, y; int i, j; int ANIM_SPEED = 20; Uint32 ticks; Uint32 to_wait; void myLockSurface(SDL_Surface * s) { while (SDL_MUSTLOCK(s) == 1 && SDL_LockSurface(s) < 0) SDL_Delay(10); } void myUnlockSurface(SDL_Surface * s) { if (SDL_MUSTLOCK(s)) SDL_UnlockSurface(s); } void synchro_before(SDL_Surface * s) { ticks = SDL_GetTicks(); myLockSurface(s); } void synchro_after(SDL_Surface * s) { myUnlockSurface(s); SDL_Flip(s); to_wait = SDL_GetTicks() - ticks; if (to_wait < ANIM_SPEED) { SDL_Delay(ANIM_SPEED - to_wait); } // else { printf("slow (%d)", ANIM_SPEED - to_wait); } } void fb__out_of_memory(void) { fprintf(stderr, "**ERROR** Out of memory\n"); abort(); } int rand_(double val) { return 1+(int) (val*rand()/(RAND_MAX+1.0)); } /************************** Graphical effects ****************************/ /* * Features: * * - plasma-ordered fill (with top-bottom and/or left-right mirrored plasma's) * - random points * - horizontal blinds * - vertical blinds * - center=>edge circle * - up=>down bars * - top-left=>bottom-right squares * */ /* -------------- Double Store ------------------ */ void store_effect(SDL_Surface * s, SDL_Surface * img, int which) { void copy_line(int l) { memcpy(s->pixels + (l * s->pitch), img->pixels + (l * img->pitch), MIN(s->pitch, img->pitch)); } void copy_column(int c) { int bpp = img->format->BytesPerPixel; for (y=0; ypixels + (y * s->pitch) + (c * bpp), img->pixels + (y * img->pitch) + (c * bpp), bpp); } int step = 0; int store_thickness = 15; if (which == 1) { while (step < YRES/2/store_thickness + store_thickness) { synchro_before(s); for (i=0; i<=YRES/2/store_thickness; i++) { int v = step - i; if (v >= 0 && v < store_thickness) { copy_line((i * store_thickness) + v); copy_line(YRES - 1 - ((i * store_thickness) + v)); } } step++; synchro_after(s); } } else { while (step < XRES/2/store_thickness + store_thickness) { synchro_before(s); for (i=0; i<=XRES/2/store_thickness; i++) { int v = step - i; if (v >= 0 && v < store_thickness) { copy_column((i * store_thickness) + v); copy_column(XRES - 1 - ((i * store_thickness) + v)); } } step++; synchro_after(s); } } } /* -------------- Bars ------------------ */ void bars_effect(SDL_Surface * s, SDL_Surface * img) { const int bars_max_steps = 40; const int bars_num = 16; int bpp = img->format->BytesPerPixel; int xstep = (XRES * bpp) / bars_num; for (i=0; ipixels + (y_ * s->pitch); unsigned char *yi_ = img->pixels + (y_ * img->pitch); int y__ = YRES - 1 - y_; unsigned char *ys__ = s->pixels + (y__ * s->pitch); unsigned char *yi__ = img->pixels + (y__ * img->pitch); for (j=0; jformat->BytesPerPixel; const int squares_size = 32; int fillrect(int i, int j) { int c, vs, vi; if (i >= XRES/squares_size || j >= YRES/squares_size) return 0; vs = i*squares_size*bpp + j*squares_size*s->pitch; vi = i*squares_size*bpp + j*squares_size*img->pitch; for (c=0; cpixels + vs + c*s->pitch, img->pixels + vi + c*img->pitch, squares_size*bpp); return 1; } int still_moving = 1; for (i=0; still_moving; i++) { int k = 0; synchro_before(s); still_moving = 0; for (j=i; j>=0; j--) { if (fillrect(j, k)) still_moving = 1; k++; } synchro_after(s); } } /* -------------- Circle ------------------ */ int * circle_steps; const int circle_max_steps = 40; void circle_init(void) { int sqr(int v) { return v*v; } circle_steps = malloc(XRES * YRES * sizeof(int)); if (!circle_steps) fb__out_of_memory(); for (y=0; y= 0) { synchro_before(s); #define WITH_TYPE(UintN) \ for (y=0; ypixels + y * s->pitch); \ UintN *srcpixels = (UintN*)(img->pixels + y * img->pitch); \ for (x=0; xformat->BytesPerPixel == 1) { WITH_TYPE(Uint8); } else if (s->format->BytesPerPixel == 2) { WITH_TYPE(Uint16); } else if (s->format->BytesPerPixel == 4) { WITH_TYPE(Uint32); } #undef WITH_TYPE step--; synchro_after(s); } } /* -------------- Plasma ------------------ */ unsigned char * plasma, * plasma2; int plasma_max; const int plasma_steps = 40; void plasma_init(char * datapath) { char * finalpath; char mypath[] = "/data/plasma.raw"; FILE * f; finalpath = malloc(strlen(datapath) + sizeof(mypath) + 1); if (!finalpath) fb__out_of_memory(); sprintf(finalpath, "%s%s", datapath, mypath); f = fopen(finalpath, "rb"); free(finalpath); if (!f) { fprintf(stderr, "Ouch, could not open plasma.raw for reading\n"); exit(1); } plasma = malloc(XRES * YRES); if (!plasma) fb__out_of_memory(); if (fread(plasma, 1, XRES * YRES, f) != XRES * YRES) { fprintf(stderr, "Ouch, could not read %d bytes from plasma file\n", XRES * YRES); exit(1); } plasma_max = -1; for (x=0; x plasma_max) plasma_max = plasma[x+y*XRES]; for (y=0; ypixels + y * s->pitch); \ UintN *ipix = (UintN *)(img->pixels + y * img->pitch); \ if (rnd_plasma == 1) { \ for (x=0; xpixels + y * s->pitch); \ UintN *ipix = (UintN*)(img->pixels + y * img->pitch); \ for (x=0; xformat->BytesPerPixel == 1) { WITH_TYPE(Uint16); } else if (s->format->BytesPerPixel == 2) { WITH_TYPE(Uint16); } else if (s->format->BytesPerPixel == 4) { WITH_TYPE(Uint32); } #undef WITH_TYPE step++; synchro_after(s); } } /************************** Shrinking image ****************************/ void shrink_(SDL_Surface * dest, SDL_Surface * orig, int xpos, int ypos, SDL_Rect * orig_rect, int factor) { int bpp = dest->format->BytesPerPixel; int rx = orig_rect->x / factor; int rw = orig_rect->w / factor; int ry = orig_rect->y / factor; int rh = orig_rect->h / factor; xpos -= rx; ypos -= ry; myLockSurface(orig); myLockSurface(dest); for (x=rx; xformat->palette) { /* there is no palette, it's cool, I can do (uber-slow) high-quality shrink */ Uint32 pixelvalue; /* this should also be okay for 16-bit and 24-bit formats */ int r = 0; int g = 0; int b = 0; for (i=0; ipixels + (x*factor+i)*bpp + (y*factor+j)*orig->pitch, bpp); r += (pixelvalue & orig->format->Rmask) >> orig->format->Rshift; g += (pixelvalue & orig->format->Gmask) >> orig->format->Gshift; b += (pixelvalue & orig->format->Bmask) >> orig->format->Bshift; } } pixelvalue = ((r/(factor*factor)) << orig->format->Rshift) + ((g/(factor*factor)) << orig->format->Gshift) + ((b/(factor*factor)) << orig->format->Bshift); memcpy(dest->pixels + (xpos+x)*bpp + (ypos+y)*dest->pitch, &pixelvalue, bpp); } else { /* there is a palette... I don't care of the bloody oldskoolers who still use 8-bit displays & al, they can suffer and die ;p */ memcpy(dest->pixels + (xpos+x)*bpp + (ypos+y)*dest->pitch, orig->pixels + (x*factor)*bpp + (y*factor)*orig->pitch, bpp); } } } myUnlockSurface(orig); myUnlockSurface(dest); } /************************** Gateway to Perl ****************************/ MODULE = fb_c_stuff PACKAGE = fb_c_stuff PROTOTYPES : DISABLE void init_effects(datapath) char * datapath CODE: circle_init(); plasma_init(datapath); srand(time(NULL)); void effect(s, img, randvalue) SDL_Surface * s SDL_Surface * img int randvalue CODE: if (s->format->BytesPerPixel != img->format->BytesPerPixel) { fprintf(stderr, "Surface format mismatch!\n\t s->format->BytesPerPixel = %d\n\timg->format->BytesPerPixel = %d\n", s->format->BytesPerPixel, img->format->BytesPerPixel); } else if (s->format->BytesPerPixel == 1 || s->format->BytesPerPixel == 2 || s->format->BytesPerPixel == 4) { switch (randvalue % 7) { case 0: squares_effect(s, img);break; case 1: store_effect(s, img, 0);break; case 2: store_effect(s, img, 1);break; case 3: plasma_effect(s, img, 0);break; case 4: plasma_effect(s, img, 1);break; case 5: circle_effect(s, img);break; case 6: bars_effect(s, img);break; } } else { switch (randvalue % 4) { case 0: squares_effect(s, img);break; case 1: store_effect(s, img, 0);break; case 2: store_effect(s, img, 1);break; case 3: bars_effect(s, img);break; } } int get_synchro_value() CODE: RETVAL = Mix_GetSynchroValue(); OUTPUT: RETVAL void set_music_position(pos) double pos CODE: Mix_SetMusicPosition(pos); int fade_in_music_position(music, loops, ms, pos) Mix_Music *music int loops int ms int pos CODE: RETVAL = Mix_FadeInMusicPos(music, loops, ms, pos); OUTPUT: RETVAL void shrink(dest, orig, xpos, ypos, orig_rect, factor) SDL_Surface * dest SDL_Surface * orig int xpos int ypos SDL_Rect * orig_rect int factor CODE: shrink_(dest, orig, xpos, ypos, orig_rect, factor); void _exit(status) int status void fbdelay(ms) int ms CODE: /* Beuh, SDL::App::delay is bugged, sometimes it doesn't sleep, must be related to signals or something... but doing the do/while in Perl seems to slow down the game too much on some machines, so I'll do it from here */ int then; do { then = SDL_GetTicks(); SDL_Delay(ms); ms -= SDL_GetTicks() - then; } while (ms > 1);