/* * EffecTV - Realtime Digital Video Effector * Copyright (C) 2001-2003 FUKUCHI Kentaro * * PuzzleTV - separates the image into blocks and scrambles them. * The blocks can be moved interactively. * * The origin of PuzzleTV is ``Video Puzzle'' by Suutarou in 1993. * It runs on Fujitsu FM-TOWNS. */ #include #include #include "EffecTV.h" #include "utils.h" static int start(void); static int stop(void); static int draw(RGB32 *src, RGB32 *dest); static int event(); #define BLOCKSIZE 80 #define SLIDING_INTERVAL 30 #define AUTOSOLVE_WAIT 300 static char *effectname = "PuzzleTV"; static int stat; static int blockSize; static int blockW; static int blockH; static int blockNum; typedef struct { int position; int srcOffset; int destOffset; } Block; static Block *blocks; static int marginW; static int marginH; static int phase; static int movingBlock; static int spaceBlock; static int autoSolveTimer; static void copyBlockImage(RGB32 *src, RGB32 *dest); static void blockSetSrcOffset(int i); static void moveBlock(RGB32 *src, RGB32 *dest); static void autoSolve(void); effect *puzzleRegister() { effect *entry; int x, y; blockSize = BLOCKSIZE; if(video_width < 320) { blockSize = video_width / 4; } if(video_height < 240) { if((video_height / 3) < blockSize) { blockSize = video_height / 3; } } blockW = video_width / blockSize; blockH = video_height / blockSize; blockNum = blockW * blockH; blocks = (Block *)malloc(blockNum * sizeof(Block)); if(blocks == NULL) { return NULL; } for(y=0; yname = effectname; entry->start = start; entry->stop = stop; entry->draw = draw; entry->event = event; return entry; } static int start() { int i, a, b, c; for(i=0; i= 0) { moveBlock(src, dest); } if(marginW) { p = src + blockW * blockSize; q = dest + blockW * blockSize; for(y=0; y= 0) return -1; x = spaceBlock % blockW; y = spaceBlock / blockW; switch(dir) { case 0: dx = 0; dy = 1; break; case 1: dx = 0; dy = -1; break; case 2: dx = 1; dy = 0; break; case 3: dx = -1; dy = 0; break; default: return -1; break; } if(x + dx < 0 || x + dx >= blockW) return -1; if(y + dy < 0 || y + dy >= blockH) return -1; movingBlock = (y + dy) * blockW + x + dx; phase = SLIDING_INTERVAL - 1; return 0; } static int event(SDL_Event *event) { if(event->type == SDL_KEYDOWN) { switch(event->key.keysym.sym) { case SDLK_w: case SDLK_k: orderMotion(0); break; case SDLK_s: case SDLK_j: orderMotion(1); break; case SDLK_a: case SDLK_h: orderMotion(2); break; case SDLK_d: case SDLK_l: orderMotion(3); break; default: break; } autoSolveTimer = AUTOSOLVE_WAIT; } return 0; } static void copyBlockImage(RGB32 *src, RGB32 *dest) { int y; for(y=blockSize; y>0; y--) { memcpy(dest, src, blockSize * PIXEL_SIZE); src += video_width; dest += video_width; } } static void blockSetSrcOffset(int i) { int x, y; x = blocks[i].position % blockW; y = blocks[i].position / blockW; blocks[i].srcOffset = (y * video_width + x) * blockSize; } static void moveBlock(RGB32 *src, RGB32 *dest) { int sx, sy; int dx, dy; int x, y; sx = movingBlock % blockW; sy = movingBlock / blockW; dx = spaceBlock % blockW; dy = spaceBlock / blockW; sx *= blockSize; sy *= blockSize; dx *= blockSize; dy *= blockSize; x = dx + (sx - dx) * phase / SLIDING_INTERVAL; y = dy + (sy - dy) * phase / SLIDING_INTERVAL; copyBlockImage(src + blocks[movingBlock].srcOffset, dest + y * video_width + x); if(autoSolveTimer == 0) { phase--; } else { phase-=2; } if(phase < 0) { int tmp; /* Exchanges positions of the moving block and the space */ tmp = blocks[movingBlock].position; blocks[movingBlock].position = blocks[spaceBlock].position; blocks[spaceBlock].position = tmp; blockSetSrcOffset(movingBlock); blockSetSrcOffset(spaceBlock); spaceBlock = movingBlock; movingBlock = -1; } } static void autoSolve(void) { /* IMPORTANT BUG: this functions does *NOT* solve the puzzle! */ static int lastMove = 0; static char dir[4]; int i, j, x, y, max; if(movingBlock >= 0) return; for(i=0; i<4; i++) { dir[i] = i; } dir[lastMove] = -1; x = spaceBlock % blockW; y = spaceBlock / blockW; if(x <= 0) dir[3] = -1; if(x >= blockW - 1) dir[2] = -1; if(y <= 0) dir[1] = -1; if(y >= blockH - 1) dir[0] = -1; max = 0; for(i=0; i<3; i++) { if(dir[i] == -1) { for(j=i+1; j<4; j++) { if(dir[j] != -1) { dir[i] = dir[j]; dir[j] = -1; max++; break; } } } else { max++; } } if(max > 0) { i = dir[inline_fastrand() % max]; if(orderMotion(i) == 0) { if(i < 2) { lastMove = 1 - i; } else { lastMove = 5 - i; } } } }