246 lines
6.2 KiB
C
246 lines
6.2 KiB
C
#include <SDL.h>
|
|
|
|
#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;
|
|
}
|
|
|