# HG changeset patch # User John Tsiombikas # Date 1316838127 -10800 # Node ID 1c8eb90a698933109711a6e4d6a1576cf209e1d1 initial commit diff -r 000000000000 -r 1c8eb90a6989 .hgignore --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.hgignore Sat Sep 24 07:22:07 2011 +0300 @@ -0,0 +1,6 @@ +\.o$ +\.d$ +\.swp$ +^Makefile$ +^libpsys\.a$ +^libpsys\.so\. diff -r 000000000000 -r 1c8eb90a6989 Makefile.in --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Makefile.in Sat Sep 24 07:22:07 2011 +0300 @@ -0,0 +1,45 @@ +src = $(wildcard src/*.c) +obj = $(src:.c=.o) +lib_a = libpsys.a +lib_so = libpsys.so + +CC = gcc +CFLAGS = -std=c89 -pedantic -Wall -g -fPIC -Isrc `pkg-config --cflags vmath` +LDFLAGS = `pkg-config --libs vmath` + +.PHONY: all +all: $(lib_a) $(lib_so) + +$(lib_a): $(obj) + $(AR) rcs $@ $^ + +$(lib_so): $(obj) + $(CC) $(CFLAGS) -shared -o $@ $^ $(LDFLAGS) + +.PHONY: install +install: $(lib_a) $(lib_so) + install -d $(PREFIX)/lib + install -m 644 $(lib_a) $(lib_so) $(PREFIX)/lib + install -d $(PREFIX)/include + install -m 644 src/psys.h $(PREFIX)/include/psys.h + install -d $(PREFIX)/lib/pkgconfig + install -m 644 psys.pc $(PREFIX)/lib/pkgconfig/psys.pc + +.PHONY: uninstall +uninstall: + rm -f $(PREFIX)/lib/$(lib_a) + rm -f $(PREFIX)/lib/$(lib_so) + rm -f $(PREFIX)/include/psys.h + rm -f $(PREFIX)/lib/pkgconfig/psys.pc + +.PHONY: clean +clean: + rm -f $(obj) + +.PHONY: distclean +distclean: + rm -f $(obj) $(lib_so) $(lib_a) Makefile psys.pc + +.PHONY: dist +dist: distclean + cd ..; tar czvf psys.tar.gz psys && mv psys.tar.gz psys/ diff -r 000000000000 -r 1c8eb90a6989 README --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/README Sat Sep 24 07:22:07 2011 +0300 @@ -0,0 +1,1 @@ +libpsys - 0.1 diff -r 000000000000 -r 1c8eb90a6989 configure --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/configure Sat Sep 24 07:22:07 2011 +0300 @@ -0,0 +1,71 @@ +#!/bin/sh + +PREFIX=/usr/local +OPT=yes +DBG=yes +VERSION=`head -1 README | sed 's/^.*- //'` + +echo "configuring psys $VERSION ..." + +check_vmath() +{ + PKG_CONFIG_PATH=$PKG_CONFIG_PATH:/usr/lib/pkgconfig:/usr/local/lib/pkgconfig:/usr/nekoware/lib/pkgconfig:/usr/freeware/lib/pkgconfig:/opt/lib/pkgconfig + if [ -z "`pkg-config --cflags vmath`" ]; then + echo 'libpsys depends on libvmath. You must install libvmath first.' + exit 1 + fi +} + +for arg; do + case "$arg" in + --prefix=*) + value=`echo $arg | sed 's/--prefix=//'` + PREFIX=${value:-$PREFIX} + ;; + + --enable-opt) + OPT=yes;; + --disable-opt) + OPT=no;; + + --enable-debug) + DBG=yes;; + --disable-debug) + DBG=no;; + + --help) + echo 'usage: ./configure [options]' + echo 'options:' + echo ' --prefix=: installation path (default: /usr/local)' + echo ' --enable-opt: enable speed optimizations (default)' + echo ' --disable-opt: disable speed optimizations' + echo ' --enable-debug: include debugging symbols (default)' + echo ' --disable-debug: do not include debugging symbols' + echo 'all invalid options are silently ignored' + exit 0 + ;; + esac +done + +check_vmath + +echo "prefix: $PREFIX" +echo "optimize for speed: $OPT" +echo "include debugging symbols: $DBG" + +echo 'creating makefile ...' +echo "PREFIX = $PREFIX" >Makefile +if [ "$DBG" = 'yes' ]; then + echo 'dbg = -g' >>Makefile +fi +if [ "$OPT" = 'yes' ]; then + echo 'opt = -O3' >>Makefile +fi +cat Makefile.in >>Makefile + +echo 'creating pkg-config file ...' +echo "prefix=$PREFIX" >psys.pc +echo "ver=$VERSION" >>psys.pc +cat psys.pc.in >>psys.pc + +echo 'configuration completed, type make (or gmake) to build.' diff -r 000000000000 -r 1c8eb90a6989 src/psys.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/psys.c Sat Sep 24 07:22:07 2011 +0300 @@ -0,0 +1,374 @@ +#include +#include +#include +#include +#include +#include "psys_impl.h" + +static int spawn(struct psys_emitter *em, struct psys_particle *p, void *cls); +static void update_particle(struct psys_emitter *em, struct psys_particle *p, float tm, float dt, void *cls); + +static int init_v3track(struct v3track *v3t); +static void destroy_v3track(struct v3track *v3t); +static void set_v3value(struct v3track *v3t, anm_time_t tm, vec3_t v); +static vec3_t get_v3value(struct v3track *v3t, anm_time_t tm); + +/* particle pool */ +static struct psys_particle *ppool; +static int ppool_size; +static pthread_mutex_t pool_lock = PTHREAD_MUTEX_INITIALIZER; + +static struct psys_particle *palloc(void); +static void pfree(struct psys_particle *p); + +/* --- constructors and shit --- */ + +struct psys_emitter *psys_create(void) +{ + struct psys_emitter *em; + + if(!(em = malloc(sizeof *em))) { + return 0; + } + if(psys_init(em) == -1) { + free(em); + return 0; + } + return em; +} + +void psys_free(struct psys_emitter *em) +{ + psys_destroy(em); + free(em); +} + +int psys_init(struct psys_emitter *em) +{ + memset(em, 0, sizeof *em); + + if(anm_init_node(&em->prs) == -1) { + return -1; + } + if(anm_init_track(&em->rate) == -1) { + anm_destroy_node(&em->prs); + return -1; + } + if(init_v3track(&em->dir) == -1) { + anm_destroy_node(&em->prs); + anm_destroy_track(&em->rate); + return -1; + } + + em->spawn = spawn; + em->update = update_particle; + + em->draw = psys_gl_draw; + em->draw_start = psys_gl_draw_start; + em->draw_end = psys_gl_draw_end; + + return 0; +} + +void psys_destroy(struct psys_emitter *em) +{ + struct psys_particle *part; + + part = em->plist; + while(part) { + struct psys_particle *tmp = part; + part = part->next; + pfree(tmp); + } + + anm_destroy_node(&em->prs); + anm_destroy_track(&em->rate); + destroy_v3track(&em->dir); +} + +void psys_set_pos(struct psys_emitter *em, vec3_t pos, float tm) +{ + anm_set_position(&em->prs, pos, ANM_SEC2TM(tm)); +} + +void psys_set_rot(struct psys_emitter *em, quat_t rot, float tm) +{ + anm_set_rotation(&em->prs, rot, ANM_SEC2TM(tm)); +} + +void psys_set_pivot(struct psys_emitter *em, vec3_t pivot) +{ + anm_set_pivot(&em->prs, pivot); +} + +void psys_set_rate(struct psys_emitter *em, float rate, float tm) +{ + anm_set_value(&em->rate, ANM_SEC2TM(tm), rate); +} + +void psys_set_dir(struct psys_emitter *em, vec3_t dir, float tm) +{ + set_v3value(&em->dir, ANM_SEC2TM(tm), dir); +} + + +void psys_clear_collision_planes(struct psys_emitter *em) +{ + struct col_plane *plane; + + plane = em->planes; + while(plane) { + struct col_plane *tmp = plane; + plane = plane->next; + pfree(tmp); + } +} + +int psys_add_collision_plane(struct psys_emitter *em, plane_t plane, float elast) +{ + struct col_plane *node; + + if(!(node = malloc(sizeof *node))) { + return -1; + } + node->p = plane; + node->elasticity = elast; + node->next = em->planes; + em->planes = node; + return 0; +} + +void psys_add_particle(struct psys_emitter *em, struct psys_particle *p) +{ + p->next = em->plist; + em->plist = p; +} + +void psys_spawn_func(struct psys_emitter *em, psys_spawn_func_t func, void *cls) +{ + em->spawn = func; + em->spawn_cls = cls; +} + +void psys_update_func(struct psys_emitter *em, psys_update_func_t func, void *cls) +{ + em->update = func; + em->upd_cls = cls; +} + +void psys_draw_func(struct psys_emitter *em, psys_draw_func_t draw, + psys_draw_start_func_t start, psys_draw_end_func_t end, void *cls) +{ + em->draw = draw; + em->draw_start = start; + em->draw_end = end; + em->draw_cls = cls; +} + +/* --- query current state --- */ +vec3_t psys_get_pos(struct psys_emitter *em) +{ + return em->cur_pos; +} + +quat_t psys_get_rot(struct psys_emitter *em) +{ + return em->cur_rot; +} + +float psys_get_rate(struct psys_emitter *em) +{ + return em->cur_rate; +} + +float psys_get_life(struct psys_emitter *em) +{ + return em->cur_life; +} + +vec3_t psys_get_dir(struct psys_emitter *em) +{ + return em->cur_dir; +} + + +/* --- update and render --- */ + +void psys_update(struct psys_emitter *em, float tm) +{ + float dt, spawn_dt; + int i, spawn_count; + struct psys_particle *p, pdummy; + anm_time_t atm; + + assert(em->spawn && em->update); + + atm = ANM_SEC2TM(tm); + + em->cur_rate = anm_get_value(&em->rate, atm) + dt = tm - em->last_update; + + /* how many particles to spawn for this interval ? */ + spawn_count = em->cur_rate * dt; + +#ifndef SUB_UPDATE_POS + em->pos = anm_get_position(&em->prs, atm); +#endif + em->cur_dir = get_v3value(&em->dir, atm); + em->cur_life = anm_get_value(&em->life, atm); + + spawn_dt = dt / (float)spawn_count; + for(i=0; ipos = anm_get_position(&em->prs, ANM_SEC2TM(em->last_update + spawn_dt)); +#endif + + if(!(p = palloc())) { + return; + } + if(em->spawn(em, p, em->spawn_cls) == -1) { + pfree(p); + } + } + + /* update all particles */ + p = em->plist; + while(p) { + em->update(em, p, tm, dt, upd_cls); + p = p->next; + } + + /* cleanup dead particles */ + pdummy.next = em->plist; + p = &pdummy; + while(p->next) { + if(p->next->life <= 0) { + struct psys_particle *tmp = p->next; + p->next = p->next->next; + pfree(tmp); + } else { + p = p->next; + } + } + em->plist = pdummy.next; +} + +void psys_draw(struct psys_emitter *em) +{ + struct psys_particle *p; + + if(em->draw_start) { + em->draw_start(em, em->cls); + } + + p = em->plist; + while(p) { + em->draw(em, p, em->cls); + p = p->next; + } + + if(em->draw_end) { + em->draw_end(em, em->cls); + } +} + +static int spawn(struct psys_emitter *em, struct psys_particle *p, void *cls) +{ + p->pos = em->cur_pos; + p->vel = em->cur_dir; + p->size = 1.0; + p->life = em->cur_life; + + psys_add_particle(em, p); + return 0; +} + +static void update_particle(struct psys_emitter *em, struct psys_particle *p, float tm, float dt, void *cls) +{ + vec3_t forces; + + forces.x = em->cur_grav.x * p->mass - p->vel.x * em->drag; + forces.y = em->cur_grav.y * p->mass - p->vel.y * em->drag; + forces.z = em->cur_grav.z * p->mass - p->vel.z * em->drag; + + p->pos.x += p->vel.x * dt; + p->pos.y += p->vel.y * dt; + p->pos.z += p->vel.z * dt; + + +} + +/* --- v3track helper --- */ + +int init_v3track(struct v3track *v3t) +{ + if(anm_init_track(&v3t->x) == -1) { + return -1; + } + if(anm_init_track(&v3t->y) == -1) { + anm_destroy_track(&v3t->x); + return -1; + } + if(anm_init_track(&v3t->z) == -1) { + anm_destroy_track(&v3t->x); + anm_destroy_track(&v3t->y); + return -1; + } + return 0; +} + +static void destroy_v3track(struct v3track *v3t) +{ + anm_destroy_track(&v3t->x); + anm_destroy_track(&v3t->y); + anm_destroy_track(&v3t->z); +} + +static void set_v3value(struct v3track *v3t, anm_time_t tm, vec3_t v) +{ + anm_set_value(&v3t->x, tm, v.x); + anm_set_value(&v3t->y, tm, v.y); + anm_set_value(&v3t->z, tm, v.z); +} + +static vec3_t get_v3value(struct v3track *v3t, anm_time_t tm) +{ + vec3_t v; + v.x = anm_get_value(&v3t->x, tm); + v.y = anm_get_value(&v3t->y, tm); + v.z = anm_get_value(&v3t->z, tm); + return v; +} + +/* --- particle allocation pool --- */ + +static struct psys_particle *palloc(void) +{ + struct psys_particle *p; + + pthread_mutex_lock(&pool_lock); + if(ppool) { + p = ppool; + ppool = ppool->next; + ppool_size--; + } else { + p = malloc(sizeof *p); + } + pthread_mutex_unlock(&pool_lock); + + if(p) { + memset(p, 0, sizeof *p); + reset_pattr(&p->attr); + } + return p; +} + +static void pfree(struct psys_particle *p) +{ + pthread_mutex_lock(&pool_lock); + p->next = ppool; + ppool = p; + ppool_size++; + pthread_mutex_unlock(&pool_lock); +} diff -r 000000000000 -r 1c8eb90a6989 src/psys.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/psys.h Sat Sep 24 07:22:07 2011 +0300 @@ -0,0 +1,61 @@ +#ifndef LIBPSYS_H_ +#define LIBPSYS_H_ + +/* emitter properties: + * - p/r/s (anim) + * - spawn rate (anim) + * - direction (anim) + * + * - collision planes + */ + +struct psys_emitter; +struct psys_particle; + +typedef int (*psys_spawn_func_t)(struct psys_emitter*, struct psys_particle*, void*); +typedef void (*psys_update_func_t)(struct psys_emitter*, struct psys_particle*, float, float, void*); + +typedef void (*psys_draw_func_t)(struct psys_emitter*, struct psys_particle*, void*); +typedef void (*psys_draw_start_func_t)(struct psys_emitter*, void*); +typedef void (*psys_draw_end_func_t)(struct psys_emitter*, void*); + + +struct psys_emitter *psys_create(void); +void psys_free(struct psys_emitter *em); + +int psys_init(struct psys_emitter *em); +void psys_destroy(struct psys_emitter *em); + +/* set properties */ + +void psys_set_pos(struct psys_emitter *em, vec3_t pos, float tm); +void psys_set_rot(struct psys_emitter *em, quat_t rot, float tm); +void psys_set_pivot(struct psys_emitter *em, vec3_t pivot); + +void psys_set_rate(struct psys_emitter *em, float rate, float tm); +void psys_set_dir(struct psys_emitter *em, vec3_t dir, float tm); + +void psys_clear_collision_planes(struct psys_emitter *em); +int psys_add_collision_plane(struct psys_emitter *em, plane_t plane, float elast); + +void psys_add_particle(struct psys_emitter *em, struct psys_particle *p); + +void psys_spawn_func(struct psys_emitter *em, psys_spawn_func_t func, void *cls); +void psys_update_func(struct psys_emitter *em, psys_update_func_t func, void *cls); +void psys_draw_func(struct psys_emitter *em, psys_draw_func_t draw, + psys_draw_start_func_t start, psys_draw_end_func_t end, void *cls); + + +/* query emitter state */ +vec3_t psys_get_pos(struct psys_emitter *em); +quat_t psys_get_rot(struct psys_emitter *em); +float psys_get_rate(struct psys_emitter *em); +float psys_get_life(struct psys_emitter *em); +vec3_t psys_get_dir(struct psys_emitter *em); + +/* update and render */ + +void psys_update(struct psys_emitter *em, float tm); +void psys_draw(struct psys_emitter *em); + +#endif /* LIBPSYS_H_ */ diff -r 000000000000 -r 1c8eb90a6989 src/psys_gl.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/psys_gl.c Sat Sep 24 07:22:07 2011 +0300 @@ -0,0 +1,57 @@ +#ifndef __APPLE__ +#include +#else +#include +#endif + +#include "psys_impl.h" + +void psys_gl_draw_start(struct psys_emitter *em, void *cls) +{ + float xform[16]; + + glMatrixMode(GL_MODELVIEW); + glPushMatrix(); + + glGetFloatv(GL_MODELVIEW_MATRIX, xform); + xform[3] = xform[7] = xform[11] = xform[12] = xform[13] = xform[14] = 0.0f; + xform[15] = 1.0f; + + glLoadMatrixf(xform); + + glPushAttrib(GL_ENABLE_BIT); + glDisable(GL_LIGHTING); + + glDepthMask(0); + + glBegin(GL_QUADS); + glColor3f(1, 1, 1); +} + +void psys_gl_draw(struct psys_emitter *em, struct psys_particle *p, void *cls) +{ + float hsz = p->size / 2.0; + + glTexCoord2f(0, 0); + glVertex3f(p->pos.x - hsz, p->pos.y - hsz, p->pos.z); + + glTexCoord2f(1, 0); + glVertex3f(p->pos.x + hsz, p->pos.y - hsz, p->pos.z); + + glTexCoord2f(1, 1); + glVertex3f(p->pos.x + hsz, p->pos.y + hsz, p->pos.z); + + glTexCoord2f(0, 1); + glVertex3f(p->pos.x - hsz, p->pos.y + hsz, p->pos.z); +} + +void psys_gl_draw_end(struct psys_emitter *em, void *cls) +{ + glEnd(); + + glDepthMask(1); + glPopAttrib(); + + glMatrixMode(GL_MODELVIEW); + glPopMatrix(); +} diff -r 000000000000 -r 1c8eb90a6989 src/psys_impl.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/psys_impl.h Sat Sep 24 07:22:07 2011 +0300 @@ -0,0 +1,68 @@ +#ifndef PSYS_IMPL_H_ +#define PSYS_IMPL_H_ + +#include +#include "psys.h" + +struct v3track { + struct anm_track x, y, z; +}; + +struct col_plane { + plane_t p; + float elasticity; + struct col_plane *next; +}; + +struct psys_particle; + +struct psys_emitter { + float last_update; + + struct anm_node prs; + + struct anm_track rate; + struct anm_track life; + struct v3track dir; + struct v3track grav; + + float drag; /* I don't think this needs to animate */ + + /* list of active particles */ + struct psys_particle *plist; + + /* list of collision planes */ + struct col_plane *planes; + + /* custom spawn closure */ + void *spawn_cls; + psys_spawn_func_t spawn; + + /* custom particle update closure */ + void *upd_cls; + psys_update_func_t update; + + /* custom draw closure */ + void *draw_cls; + psys_draw_func_t draw; + psys_draw_start_func_t draw_start; + psys_draw_end_func_t draw_end; + + /* calculated on update */ + vec3_t cur_pos; + qut_t cur_rot; + float cur_rate, cur_life; + vec3_t cur_dir; +}; + + +struct psys_particle { + vec3_t pos, vel; + float life, size, mass; +}; + +void psys_gl_draw_start(struct psys_emitter *em, void *cls); +void psys_gl_draw(struct psys_emitter *em, struct psys_particle *p, void *cls); +void psys_gl_draw_end(struct psys_emitter *em, void *cls); + +#endif /* PSYS_IMPL_H_ */