#include #include "lephisto.h" #include "log.h" #include "pilot.h" #include "physics.h" #include "opengl.h" #include "pause.h" #include "spfx.h" #define SPFX_GFX "../gfx/spfx/" // Graphics location. #define SPFX_CHUNK 10 // Chunk to allocate when needed. typedef struct SPFX_Base_ { char* name; int anim; // Total duration in ms. glTexture* gfx; // Will use each sprite as a frame. } SPFX_Base; static SPFX_Base* spfx_effects = NULL; static int spfx_neffects = 0; typedef struct SPFX_ { Vec2 pos, vel; // They don't accelerate. int lastframe; // Need when pausing. int effect; // Actual effect. unsigned int t; // Start. } SPFX; // Front stack is for effects on player. // Back is for everything else. static SPFX* spfx_stack_front = NULL; static int spfx_nstack_front = 0; static int spfx_mstack_front = 0; static SPFX* spfx_stack_back = NULL; static int spfx_nstack_back = 0; static int spfx_mstack_back = 0; static int spfx_base_load(char* name, int anim, char* gfx, int sx, int sy); static void spfx_base_free(SPFX_Base* effect); static void spfx_destroy(SPFX* layer, int* nlayer, int spfx); static void spfx_update_layer(SPFX* layer, int* nlayer, const double dt); static void spfx_pause_layer(SPFX* layer, int nlayer); static void spfx_unpause_layer(SPFX* layer, int nlayer); static void spfx_delay_layer(SPFX* layer, int nlayer, unsigned int delay); // Load the SPFX_Base. static int spfx_base_load(char* name, int anim, char* gfx, int sx, int sy) { SPFX_Base* cur; char buf[PATH_MAX]; spfx_effects = realloc(spfx_effects, ++spfx_neffects*sizeof(SPFX_Base)); cur = &spfx_effects[spfx_neffects-1]; cur->name = strdup(name); cur->anim = anim; sprintf(buf, SPFX_GFX"%s", gfx); cur->gfx = gl_newSprite(buf, sx, sy); return 0; } static void spfx_base_free(SPFX_Base* effect) { if(effect->name) free(effect->name); if(effect->gfx) gl_freeTexture(effect->gfx); } int spfx_get(char* name) { int i; for(i = 0; i < spfx_neffects; i++) if(strcmp(spfx_effects[i].name, name)==0) return i; WARN("SPFX '%s' not found!", name); return 0; } // Load/Unload. int spfx_load(void) { spfx_base_load("ExpS", 400, "exps.png", 6, 5); spfx_base_load("ExpM", 450, "expm.png", 6, 5); spfx_base_load("ExpL", 500, "expl.png", 6, 5); return 0; } void spfx_free(void) { int i; // Get rid of all the particles and free the stacks. spfx_clear(); if(spfx_stack_front) free(spfx_stack_front); spfx_stack_front = NULL; spfx_mstack_front = 0; if(spfx_stack_back) free(spfx_stack_back); spfx_stack_back = NULL; spfx_mstack_back = 0; for(i = 0; i < spfx_neffects; i++) spfx_base_free(&spfx_effects[i]); free(spfx_effects); spfx_effects = NULL; spfx_neffects = 0; } void spfx_add(int effect, const double px, const double py, const double vx, const double vy, const int layer) { SPFX* cur_spfx; if(layer == SPFX_LAYER_FRONT) { // Front layer. if(spfx_mstack_front < spfx_nstack_front+1) { // We need more memory. spfx_mstack_front += SPFX_CHUNK; spfx_stack_front = realloc(spfx_stack_front, spfx_mstack_front*sizeof(SPFX)); } cur_spfx = &spfx_stack_front[spfx_nstack_front]; spfx_nstack_front++; } else if(layer == SPFX_LAYER_BACK) { // Back layer. if(spfx_mstack_back < spfx_nstack_back+1) { // Need more memory. spfx_mstack_back += SPFX_CHUNK; spfx_stack_back = realloc(spfx_stack_back, spfx_mstack_back*sizeof(SPFX)); } cur_spfx = &spfx_stack_back[spfx_nstack_back]; spfx_nstack_back++; } cur_spfx->effect = effect; vect_csetmin(&cur_spfx->pos, px, py); vect_csetmin(&cur_spfx->vel, vx, vy); cur_spfx->t = SDL_GetTicks(); } void spfx_clear(void) { int i; for(i = spfx_nstack_front-1; i >= 0; i--) spfx_destroy(spfx_stack_front, &spfx_nstack_front, i); for(i = spfx_nstack_back-1; i >= 0; i--) spfx_destroy(spfx_stack_back, &spfx_nstack_back, i); } static void spfx_destroy(SPFX* layer, int* nlayer, int spfx) { (*nlayer)--; memmove(&layer[spfx], &layer[spfx+1], (*nlayer-spfx)*sizeof(SPFX)); } void spfx_update(const double dt) { spfx_update_layer(spfx_stack_front, &spfx_nstack_front, dt); spfx_update_layer(spfx_stack_back, &spfx_nstack_back, dt); } static void spfx_update_layer(SPFX* layer, int* nlayer, const double dt) { int i; unsigned int t = SDL_GetTicks(); for(i = 0; i < *nlayer; i++) { // Time to die!!! if(t > (layer[i].t + spfx_effects[layer[i].effect].anim)) { spfx_destroy(layer, nlayer, i); i--; continue; } // Mkay. Update it now. vect_cadd(&layer[i].pos, dt*VX(layer[i].vel), dt*VY(layer[i].vel)); } } void spfx_render(const int layer) { SPFX* spfx_stack; int i, spfx_nstack; SPFX_Base* effect; int sx, sy; unsigned int t = SDL_GetTicks(); // Get the appropriate layer. switch(layer) { case SPFX_LAYER_FRONT: spfx_stack = spfx_stack_front; spfx_nstack = spfx_nstack_front; break; case SPFX_LAYER_BACK: spfx_stack = spfx_stack_back; spfx_nstack = spfx_nstack_back; break; } for(i = 0; i < spfx_nstack; i++) { effect = &spfx_effects[spfx_stack[i].effect]; sx = (int)effect->gfx->sx; sy = (int)effect->gfx->sy; if(!paused) // Don't calculate frame if paused. spfx_stack[i].lastframe = sx * sy * MIN(((double)(t - spfx_stack[i].t)/(double)effect->anim), 1.); gl_blitSprite(effect->gfx, VX(spfx_stack[i].pos), VY(spfx_stack[i].pos), spfx_stack[i].lastframe % sx, spfx_stack[i].lastframe / sx, NULL); } } void spfx_pause(void) { spfx_pause_layer(spfx_stack_front, spfx_nstack_front); spfx_pause_layer(spfx_stack_back, spfx_nstack_back); } static void spfx_pause_layer(SPFX* layer, int nlayer) { int i; unsigned int t = SDL_GetTicks(); for(i = 0; i < nlayer; i++) layer[i].t -= t; } void spfx_unpause(void) { spfx_unpause_layer(spfx_stack_front, spfx_nstack_front); spfx_unpause_layer(spfx_stack_back, spfx_nstack_back); } static void spfx_unpause_layer(SPFX* layer, int nlayer) { int i; unsigned int t = SDL_GetTicks(); for(i = 0; i < nlayer; i++) layer[i].t += t; } void spfx_delay(unsigned int delay) { spfx_delay_layer(spfx_stack_front, spfx_nstack_front, delay); spfx_delay_layer(spfx_stack_back, spfx_nstack_back, delay); } static void spfx_delay_layer(SPFX* layer, int nlayer, unsigned int delay) { int i; for(i = 0; i < nlayer; i++) layer[i].t += delay; }