Forked from
tome / Tales of MajEyal
13445 commits behind the upstream repository.
-
dg authored
git-svn-id: http://svn.net-core.org/repos/t-engine4@1424 51575b47-30f0-44d4-a5cc-537603b46e54
dg authoredgit-svn-id: http://svn.net-core.org/repos/t-engine4@1424 51575b47-30f0-44d4-a5cc-537603b46e54
particles.c 11.20 KiB
/*
TE4 - T-Engine 4
Copyright (C) 2009, 2010 Nicolas Casalini
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
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, see <http://www.gnu.org/licenses/>.
Nicolas Casalini "DarkGod"
darkgod@te4.org
*/
#include "display.h"
#include "lua.h"
#include "lauxlib.h"
#include "lualib.h"
#include "auxiliar.h"
#include "types.h"
#include "particles.h"
#include "script.h"
#include <math.h>
#include "SFMT.h"
#define rng(x, y) (x + rand_div(1 + y - x))
#define PARTICLE_ETERNAL 999999
static void getinitfield(lua_State *L, const char *key, int *min, int *max)
{
lua_pushstring(L, key);
lua_gettable(L, -2);
lua_pushnumber(L, 1);
lua_gettable(L, -2);
*min = (int)lua_tonumber(L, -1);
lua_pop(L, 1);
lua_pushnumber(L, 2);
lua_gettable(L, -2);
*max = (int)lua_tonumber(L, -1);
lua_pop(L, 1);
// printf("%s :: %d %d\n", key, (int)*min, (int)*max);
lua_pop(L, 1);
}
static void getparticulefield(lua_State *L, const char *k, float *v)
{
lua_pushstring(L, k);
lua_gettable(L, -2);
*v = (float)lua_tonumber(L, -1);
// printf("emit %s :: %f\n", k, *v);
lua_pop(L, 1);
}
static int particles_new(lua_State *L)
{
int nb = luaL_checknumber(L, 1);
bool no_stop = lua_toboolean(L, 2);
int density = luaL_checknumber(L, 3);
GLuint *t = (GLuint*)auxiliar_checkclass(L, "gl{texture}", 5);
int t_ref = luaL_ref(L, LUA_REGISTRYINDEX);
int p_ref = luaL_ref(L, LUA_REGISTRYINDEX);
particles_type *ps = (particles_type*)lua_newuserdata(L, sizeof(particles_type));
auxiliar_setclass(L, "core{particles}", -1);
ps->density = density;
nb = (nb * ps->density) / 100;
if (!nb) nb = 1;
ps->nb = nb;
ps->texture = *t;
ps->texture_ref = t_ref;
ps->no_stop = no_stop;
ps->particles = calloc(nb, sizeof(particle_type));
// printf("Making particle emitter with %d particles\n", ps->nb);
// Grab all parameters
lua_rawgeti(L, LUA_REGISTRYINDEX, p_ref);
lua_pushstring(L, "generator");
lua_gettable(L, -2);
if (lua_isnil(L, -1))
{
lua_pop(L, 1);
ps->generator_ref = LUA_NOREF;
}
else
ps->generator_ref = luaL_ref(L, LUA_REGISTRYINDEX);
if (ps->generator_ref == LUA_NOREF)
{
lua_pushstring(L, "base");
lua_gettable(L, -2);
ps->base = (float)lua_tonumber(L, -1);
lua_pop(L, 1);
getinitfield(L, "life", &(ps->life_min), &(ps->life_max));
getinitfield(L, "angle", &(ps->angle_min), &(ps->angle_max));
getinitfield(L, "anglev", &(ps->anglev_min), &(ps->anglev_max));
getinitfield(L, "anglea", &(ps->anglea_min), &(ps->anglea_max));
getinitfield(L, "size", &(ps->size_min), &(ps->size_max));
getinitfield(L, "sizev", &(ps->sizev_min), &(ps->sizev_max));
getinitfield(L, "sizea", &(ps->sizea_min), &(ps->sizea_max));
getinitfield(L, "r", &(ps->r_min), &(ps->r_max));
getinitfield(L, "rv", &(ps->rv_min), &(ps->rv_max));
getinitfield(L, "ra", &(ps->ra_min), &(ps->ra_max));
getinitfield(L, "g", &(ps->g_min), &(ps->g_max));
getinitfield(L, "gv", &(ps->gv_min), &(ps->gv_max));
getinitfield(L, "ga", &(ps->ga_min), &(ps->ga_max));
getinitfield(L, "b", &(ps->b_min), &(ps->b_max));
getinitfield(L, "bv", &(ps->bv_min), &(ps->bv_max));
getinitfield(L, "ba", &(ps->ba_min), &(ps->ba_max));
getinitfield(L, "a", &(ps->a_min), &(ps->a_max));
getinitfield(L, "av", &(ps->av_min), &(ps->av_max));
getinitfield(L, "aa", &(ps->aa_min), &(ps->aa_max));
}
lua_pop(L, 1);
luaL_unref(L, LUA_REGISTRYINDEX, p_ref);
return 1;
}
static int particles_free(lua_State *L)
{
particles_type *ps = (particles_type*)auxiliar_checkclass(L, "core{particles}", 1);
free(ps->particles);
luaL_unref(L, LUA_REGISTRYINDEX, ps->texture_ref);
if (ps->generator_ref) luaL_unref(L, LUA_REGISTRYINDEX, ps->generator_ref);
lua_pushnumber(L, 1);
return 1;
}
static int particles_emit(lua_State *L)
{
particles_type *ps = (particles_type*)auxiliar_checkclass(L, "core{particles}", 1);
int nb = luaL_checknumber(L, 2);
nb = (nb * ps->density) / 100;
if (!nb) nb = 1;
int i;
for (i = 0; i < ps->nb; i++)
{
particle_type *p = &ps->particles[i];
if (!p->life)
{
if (ps->generator_ref == LUA_NOREF)
{
p->life = rng(ps->life_min, ps->life_max);
p->size = rng(ps->size_min, ps->size_max);
p->sizev = rng(ps->sizev_min, ps->sizev_max);
p->sizea = rng(ps->sizea_min, ps->sizea_max);
p->x = p->y = 0;
float angle = rng(ps->angle_min, ps->angle_max) * M_PI / 180;
float v = rng(ps->anglev_min, ps->anglev_max) / ps->base;
float a = rng(ps->anglea_min, ps->anglea_max) / ps->base;
p->xa = cos(angle) * a;
p->ya = sin(angle) * a;
p->xv = cos(angle) * v;
p->yv = sin(angle) * v;
p->dir = 0;
p->dirv = 0;
p->dira = 0;
p->vel = 0;
p->velv = 0;
p->vela = 0;
p->r = rng(ps->r_min, ps->r_max) / 255.0f;
p->g = rng(ps->g_min, ps->g_max) / 255.0f;
p->b = rng(ps->b_min, ps->b_max) / 255.0f;
p->a = rng(ps->a_min, ps->a_max) / 255.0f;
p->rv = rng(ps->rv_min, ps->rv_max) / ps->base;
p->gv = rng(ps->gv_min, ps->gv_max) / ps->base;
p->bv = rng(ps->bv_min, ps->bv_max) / ps->base;
p->av = rng(ps->av_min, ps->av_max) / ps->base;
p->ra = rng(ps->ra_min, ps->ra_max) / ps->base;
p->ga = rng(ps->ga_min, ps->ga_max) / ps->base;
p->ba = rng(ps->ba_min, ps->ba_max) / ps->base;
p->aa = rng(ps->aa_min, ps->aa_max) / ps->base;
p->trail = FALSE;
}
else
{
lua_rawgeti(L, LUA_REGISTRYINDEX, ps->generator_ref);
lua_call(L, 0, 1);
if (!lua_isnil(L, -1))
{
float life;
float trail;
getparticulefield(L, "trail", &trail); p->trail = trail;
getparticulefield(L, "life", &life); p->life = life;
getparticulefield(L, "size", &(p->size));
getparticulefield(L, "sizev", &(p->sizev));
getparticulefield(L, "sizea", &(p->sizea));
getparticulefield(L, "x", &(p->x));
getparticulefield(L, "xv", &(p->xv));
getparticulefield(L, "xa", &(p->xa));
getparticulefield(L, "y", &(p->y));
getparticulefield(L, "yv", &(p->yv));
getparticulefield(L, "ya", &(p->ya));
getparticulefield(L, "dir", &(p->dir));
getparticulefield(L, "dirv", &(p->dirv));
getparticulefield(L, "dira", &(p->dira));
getparticulefield(L, "vel", &(p->vel));
getparticulefield(L, "velv", &(p->velv));
getparticulefield(L, "vela", &(p->vela));
getparticulefield(L, "r", &(p->r));
getparticulefield(L, "rv", &(p->rv));
getparticulefield(L, "ra", &(p->ra));
getparticulefield(L, "g", &(p->g));
getparticulefield(L, "gv", &(p->gv));
getparticulefield(L, "ga", &(p->ga));
getparticulefield(L, "b", &(p->b));
getparticulefield(L, "bv", &(p->bv));
getparticulefield(L, "ba", &(p->ba));
getparticulefield(L, "a", &(p->a));
getparticulefield(L, "av", &(p->av));
getparticulefield(L, "aa", &(p->aa));
}
}
p->ox = p->x;
p->oy = p->y;
nb--;
if (!nb) break;
}
}
return 0;
}
static int particles_to_screen(lua_State *L)
{
particles_type *ps = (particles_type*)auxiliar_checkclass(L, "core{particles}", 1);
int x = luaL_checknumber(L, 2);
int y = luaL_checknumber(L, 3);
bool show = lua_toboolean(L, 4);
float zoom = luaL_checknumber(L, 5);
int w = 0;
int i, j;
bool alive = FALSE;
glBindTexture(GL_TEXTURE_2D, ps->texture);
for (w = 0; w < ps->nb; w++)
{
particle_type *p = &ps->particles[w];
if (p->life > 0)
{
alive = TRUE;
if (show)
{
glColor4f(p->r, p->g, p->b, p->a);
glBegin(GL_QUADS);
if (!p->trail)
{
i = x + p->x * zoom - p->size * zoom / 2;
j = y + p->y * zoom - p->size * zoom / 2;
glTexCoord2f(0,0); glVertex3f(0 + i, 0 + j, -97);
glTexCoord2f(1,0); glVertex3f(p->size * zoom + i, 0 + j, -97);
glTexCoord2f(1,1); glVertex3f(p->size * zoom + i, p->size * zoom + j, -97);
glTexCoord2f(0,1); glVertex3f(0 + i, p->size * zoom + j, -97);
}
else
{
if ((p->ox <= p->x) && (p->oy <= p->y))
{
glTexCoord2f(0,0); glVertex3f(0 + x + p->ox * zoom, 0 + y + p->oy * zoom, -97);
glTexCoord2f(1,0); glVertex3f(p->size * zoom + x + p->x * zoom, 0 + y + p->y * zoom, -97);
glTexCoord2f(1,1); glVertex3f(p->size * zoom + x + p->x * zoom, p->size * zoom + y + p->y * zoom, -97);
glTexCoord2f(0,1); glVertex3f(0 + x + p->x * zoom, p->size * zoom + y + p->y * zoom, -97);
}
else if ((p->ox <= p->x) && (p->oy > p->y))
{
glTexCoord2f(0,0); glVertex3f(0 + x + p->x * zoom, 0 + y + p->y * zoom, -97);
glTexCoord2f(1,0); glVertex3f(p->size * zoom + x + p->x * zoom, 0 + y + p->y * zoom, -97);
glTexCoord2f(1,1); glVertex3f(p->size * zoom + x + p->x * zoom, p->size * zoom + y + p->y * zoom, -97);
glTexCoord2f(0,1); glVertex3f(0 + x + p->ox * zoom, p->size * zoom + y + p->oy * zoom, -97);
}
else if ((p->ox > p->x) && (p->oy <= p->y))
{
glTexCoord2f(0,0); glVertex3f(0 + x + p->x * zoom, 0 + y + p->y * zoom, -97);
glTexCoord2f(1,0); glVertex3f(p->size * zoom + x + p->ox * zoom, 0 + y + p->oy * zoom, -97);
glTexCoord2f(1,1); glVertex3f(p->size * zoom + x + p->x * zoom, p->size * zoom + y + p->y * zoom, -97);
glTexCoord2f(0,1); glVertex3f(0 + x + p->x * zoom, p->size * zoom + y + p->y * zoom, -97);
}
else if ((p->ox > p->x) && (p->oy > p->y))
{
glTexCoord2f(0,0); glVertex3f(0 + x + p->x * zoom, 0 + y + p->y * zoom, -97);
glTexCoord2f(1,0); glVertex3f(p->size * zoom + x + p->x * zoom, 0 + y + p->y * zoom, -97);
glTexCoord2f(1,1); glVertex3f(p->size * zoom + x + p->ox * zoom, p->size * zoom + y + p->oy * zoom, -97);
glTexCoord2f(0,1); glVertex3f(0 + x + p->x * zoom, p->size * zoom + y + p->y * zoom, -97);
}
}
glEnd();
}
if (p->life != PARTICLE_ETERNAL) p->life--;
p->ox = p->x;
p->oy = p->y;
p->x += p->xv;
p->y += p->yv;
if (p->vel)
{
p->x += cos(p->dir) * p->vel;
p->y += sin(p->dir) * p->vel;
}
p->dir += p->dirv;
p->vel += p->velv;
p->r += p->rv;
p->g += p->gv;
p->b += p->bv;
p->a += p->av;
p->size += p->sizev;
p->xv += p->xa;
p->yv += p->ya;
p->dirv += p->dira;
p->velv += p->vela;
p->rv += p->ra;
p->gv += p->ga;
p->bv += p->ba;
p->av += p->aa;
p->sizev += p->sizea;
}
}
// Restore normal display
glColor4f(1, 1, 1, 1);
lua_pushboolean(L, alive || ps->no_stop);
return 1;
}
static const struct luaL_reg particleslib[] =
{
{"newEmitter", particles_new},
{NULL, NULL},
};
static const struct luaL_reg particles_reg[] =
{
{"__gc", particles_free},
{"close", particles_free},
{"emit", particles_emit},
{"toScreen", particles_to_screen},
{NULL, NULL},
};
int luaopen_particles(lua_State *L)
{
auxiliar_newclass(L, "core{particles}", particles_reg);
luaL_openlib(L, "core.particles", particleslib, 0);
lua_pushstring(L, "ETERNAL");
lua_pushnumber(L, PARTICLE_ETERNAL);
lua_settable(L, -3);
return 1;
}