/* * EffecTV - Realtime Digital Video Effector * Copyright (C) 2001-2003 FUKUCHI Kentaro * * spiral.c: a 'spiraling' effect (even though it isn't really a spiral) * code originally derived from quark.c; additions and changes are * copyright (c) 2001 Sam Mertens. This code is subject to the provisions of * the GNU Public License. * * --------- * 2001/04/20 * The code looks to be about done. The extra junk I add to the * title bar looks ugly - I just don't know how much to take off. * The TAB key no longer toggles animation: 'A' does. * A lot of these comments can probably be removed/reduced for the next * stable release. * --------- * 2001/04/16 * I've made quick adjustments to my most recent 'experimental' code so * it'll compile with the latest EffecTV-BSB code. More proper * intergration will commence shortly. * Animation (more accurately, automatic movement of the wave loci along * a fixed path) is implemented. I'm dissapointed by the results, though. * The following temporary additions have been made to the user interface * to allow testing of the animation: * The window title now displays the current waveform, plus * several animation parameters. Those parameters are formatted as * "(%0.2fint,%df, %dd)"; the first number is the size of the interval * between steps along the closed path. The second number is the * number of frames to wait before each step. The third number is * a quick and dirty way to control wave amplitude; wave table inspirals * are bitshifted right by that value. * The TAB key toggles animation on and off; animation is off by * default. * INSERT/DELETE increment and decrement the step interval value, * respectively. * * HOME/END increment and decrement the # of frames between each * movement of the waves' centerpoint, respectively. * * PAGE UP/PAGE DOWN increment and decrement the amount that wave table * entries are bitshifted by, respectively. * * Recent changes in the user interface: * 1. Hitting space will now cycle among 8 different wave shapes. * The active waveshape's name is displayed in the titlebar. * 2. The mouse can be used to recenter the effect. Left-clicking * moves the center of the effect (which defaults to the center * of the video image) to the mouse pointer's location. Any other * mouse button will toggle mouse visibility, so the user can see * where they're clicking. * 3. The keys '1','2','3','4' and '0' also move the effect center. * '1' through '4' move the center midway between the middle of the * image and each of the four corners, respectively. '0' returns * the center to its default position. * * -Sam Mertens */ #include #include #include #include "EffecTV.h" #include "utils.h" #ifndef max #define max(a,b) (((a) > (b)) ? (a) : (b)) #endif #ifndef M_PI #define M_PI 3.141592653589793238462643383 #endif /* M_PI */ /* Several values must be powers of 2. The *_POWER predefines keep them so. */ /* FIXME */ #define SDL_DISABLE 0 #define SQL_QUERY -1 #define PLANE_POWER (4) // 2 exp 4 = 16 #define WAVE_COUNT_POWER (3) // 2 exp 3 = 8 #define WAVE_LENGTH_POWER (9) // 2 exp 9 = 512 #define PLANES (1 << PLANE_POWER) // 16 #define PLANE_MASK (PLANES - 1) #define PLANE_MAX (PLANES - 1) #define WAVE_COUNT (1 << WAVE_COUNT_POWER) // 8 #define WAVE_MASK (WAVE_COUNT - 1) #define WAVE_MAX (WAVE_COUNT - 1) #define WAVE_LENGTH (1 << WAVE_LENGTH_POWER) // 512 #define WAVE_LENGTH_MASK (WAVE_LENGTH - 1) #define WAVE_CONCENTRIC_A 0 #define WAVE_SAWTOOTH_UP 1 #define WAVE_SAWTOOTH_DOWN 2 #define WAVE_TRIANGLE 3 #define WAVE_SINUS 4 #define WAVE_CONCENTRIC_B 5 #define WAVE_LENS 6 #define WAVE_FLAT 7 /* The *_OFFSET predefines are just precalculations. There shouldn't normally ** be any need to change them. */ #define WAVE_CONCENTRIC_A_OFFSET (WAVE_CONCENTRIC_A * WAVE_LENGTH) #define WAVE_SAW_UP_OFFSET (WAVE_SAWTOOTH_UP * WAVE_LENGTH) #define WAVE_SAW_DOWN_OFFSET (WAVE_SAWTOOTH_DOWN * WAVE_LENGTH) #define WAVE_TRIANGLE_OFFSET (WAVE_TRIANGLE * WAVE_LENGTH) #define WAVE_CONCENTRIC_B_OFFSET (WAVE_CONCENTRIC_B * WAVE_LENGTH) #define WAVE_LENS_OFFSET (WAVE_LENS * WAVE_LENGTH) #define WAVE_SINUS_OFFSET (WAVE_SINUS * WAVE_LENGTH) #define WAVE_FLAT_OFFSET (WAVE_FLAT * WAVE_LENGTH) typedef char WaveEl; #define WAVE_ELEMENT_SIZE (sizeof(WaveEl)) #define WAVE_TABLE_SIZE (WAVE_COUNT * WAVE_LENGTH * WAVE_ELEMENT_SIZE) #define FOCUS_INCREMENT_PRESET (M_PI/2.0) static int start(void); static int stop(void); static int draw(RGB32 *src, RGB32 *dest); static void spiralCreateMap(); static WaveEl* spiralDefineWaves(); static void spiralMoveFocus(); static char *effectname_base = "SpiralTV"; static char effectname[128] = ""; static int state = 0; static unsigned int *buffer; static unsigned int *planetable[PLANES]; static int plane; static int *depthmap; static int mode = 0; /* ** 'g_' is for global. I'm trying to reduce namespace pollution ** within the spiral module. ** */ static int g_focus_x = 0; static int g_focus_y = 0; static WaveEl* g_wave_table = NULL; static const char* g_wave_names[WAVE_COUNT] = { "Concentric A", "Sawtooth Up", "Sawtooth Down", "Triangle", "Sinusoidal", "Concentric B", "Lens", "Flat" }; static int g_cursor_state = SDL_DISABLE; static int g_cursor_local = SDL_DISABLE; static int g_toggle_xor = 0; static int g_animate_focus = 0; static int g_focus_interval = 6; static int g_focus_counter = 0; static unsigned int g_depth_shift = 0; // Cheesy way to adjust intensity // The following are needed only for this specific animation algorithm static int g_focus_radius = 100; static double g_focus_degree = 1.0; static double g_focus_increment = FOCUS_INCREMENT_PRESET; static void spiralSetName() { // sprintf(effectname, "%s:%s (%0.2fi/%df/%dd)", effectname_base, // g_wave_names[mode], // g_focus_increment, g_focus_interval, g_depth_shift); // screen_setcaption(effectname); } effect *spiralRegister() { effect *entry; sharedbuffer_reset(); depthmap = (int *)sharedbuffer_alloc(video_width * video_height * sizeof(int)); if(depthmap == NULL) { return NULL; } entry = (effect *)malloc(sizeof(effect)); if(entry == NULL) { free(buffer); return NULL; } strcpy(effectname, effectname_base); entry->name = effectname; entry->start = start; entry->stop = stop; entry->draw = draw; entry->event = 0; g_focus_x = (video_width/2); g_focus_y = (video_height/2); return entry; } static int start() { int i; g_focus_radius = video_width / 2; /* ** Allocate space for the frame buffers. A lot of memory is required - ** with the default settings, it totals nearly 5 megs. ** (320 * 240 * 4 * 16) = 4915200 bytes ** ** Multiply by 4 for 640x480! */ buffer = (unsigned int *)malloc(video_area * PIXEL_SIZE * PLANES); if(buffer == NULL) return -1; memset(buffer, 0, video_area * PIXEL_SIZE * PLANES); /* ** Set up the array of pointers to the frame buffers */ for(i=0;i> g_depth_shift; } } return; } static WaveEl* spiralDefineWaves() { WaveEl* wave_table; int i; int w; int iw; #ifdef PS2 float sinus_val = M_PI/2.0; #else double sinus_val = M_PI/2.0; #endif // This code feels a little like a hack, but at least it contains // all like-minded hacks in one place. wave_table = (WaveEl*)malloc(WAVE_TABLE_SIZE); if (NULL == wave_table) { return NULL; } w = ((int)sqrt(video_height * video_height + video_width * video_width)); for (i = 0; i < WAVE_LENGTH; i++) { // The 'flat' wave is very easy to compute :) wave_table[WAVE_FLAT_OFFSET + i] = 0; wave_table[WAVE_SAW_UP_OFFSET + i] = i & PLANE_MASK; wave_table[WAVE_SAW_DOWN_OFFSET + i] = PLANE_MAX - (i & PLANE_MASK); if (i & PLANES) { wave_table[WAVE_TRIANGLE_OFFSET + i] = (~i) & PLANE_MASK; } else { wave_table[WAVE_TRIANGLE_OFFSET + i] = i & PLANE_MASK; } iw = i / (w/(PLANES*2)); if (iw & PLANES) { wave_table[WAVE_CONCENTRIC_A_OFFSET + i] = (~iw) & PLANE_MASK; } else { wave_table[WAVE_CONCENTRIC_A_OFFSET + i] = iw & PLANE_MASK; } wave_table[WAVE_CONCENTRIC_B_OFFSET + i] = (i*PLANES)/w; wave_table[WAVE_LENS_OFFSET + i] = i >> 3; #ifdef PS2 wave_table[WAVE_SINUS_OFFSET + i] = ((PLANES/2) + (int)((PLANES/2 - 1) * sinf(sinus_val))) & PLANE_MASK; #else wave_table[WAVE_SINUS_OFFSET + i] = ((PLANES/2) + (int)((PLANES/2 - 1) * sin(sinus_val))) & PLANE_MASK; #endif sinus_val += M_PI/PLANES; } return (wave_table); } static void spiralMoveFocus() { g_focus_counter++; // We'll only switch maps every X frames. if (g_focus_interval <= g_focus_counter) { g_focus_counter = 0; g_focus_x = (g_focus_radius * cos(g_focus_degree)) + (video_width/2); g_focus_y = (g_focus_radius * sin(g_focus_degree*2.0)) + (video_height/2); spiralCreateMap(); g_focus_degree += g_focus_increment; if ((2.0*M_PI) <= g_focus_degree) { g_focus_degree -= (2.0*M_PI); } } return; }