dungeon_crawler
changeset 67:2560a7ab0243
internalized libanim, libimago2, and libpsys
author | John Tsiombikas <nuclear@member.fsf.org> |
---|---|
date | Sun, 07 Oct 2012 02:04:00 +0300 |
parents | fc2b3d06d07c |
children | 1141a325cb73 |
files | prototype/Makefile.in prototype/anim/anim.c prototype/anim/anim.h prototype/anim/config.h prototype/anim/dynarr.c prototype/anim/dynarr.h prototype/anim/track.c prototype/anim/track.h prototype/data/fire.psys prototype/imago2/conv.c prototype/imago2/file_jpeg.c prototype/imago2/file_png.c prototype/imago2/file_ppm.c prototype/imago2/file_rgbe.c prototype/imago2/ftype_module.c prototype/imago2/ftype_module.h prototype/imago2/imago2.c prototype/imago2/imago2.h prototype/imago2/imago_gl.c prototype/imago2/modules.c prototype/psys/pattr.c prototype/psys/pattr.h prototype/psys/pstrack.c prototype/psys/pstrack.h prototype/psys/psys.c prototype/psys/psys.h prototype/psys/psys_gl.c prototype/psys/psys_gl.h prototype/psys/rndval.c prototype/psys/rndval.h |
diffstat | 30 files changed, 4780 insertions(+), 5 deletions(-) [+] |
line diff
1.1 --- a/prototype/Makefile.in Tue Oct 02 13:42:18 2012 +0300 1.2 +++ b/prototype/Makefile.in Sun Oct 07 02:04:00 2012 +0300 1.3 @@ -1,5 +1,8 @@ 1.4 csrc = $(wildcard src/*.c) \ 1.5 $(wildcard vmath/*.c) \ 1.6 + $(wildcard imago2/*.c) \ 1.7 + $(wildcard anim/*.c) \ 1.8 + $(wildcard psys/*.c) \ 1.9 $(wildcard drawtext/*.c) \ 1.10 $(wildcard kdtree/*.c) 1.11 1.12 @@ -13,13 +16,16 @@ 1.13 1.14 warn = -Wall -Wno-format-extra-args -Wno-char-subscripts 1.15 1.16 -inc = -I. -Isrc -Ivmath -Idrawtext -Ikdtree `pkg-config --cflags freetype2` 1.17 +inc = -I. -Isrc -Ivmath -Iimago2 -Idrawtext -Ikdtree `pkg-config --cflags freetype2` 1.18 1.19 CFLAGS = -pedantic -fno-strict-aliasing $(warn) $(dbg) $(prof) $(opt) $(inc) 1.20 CXXFLAGS = $(CFLAGS) $(cxx11_cflags) 1.21 -LDFLAGS = $(cxx11_ldflags) $(prof) $(libgl) $(libal) -lvorbisfile -lm -lassimp -limago -lpsys `pkg-config --libs freetype2` 1.22 +LDFLAGS = $(cxx11_ldflags) $(prof) $(libgl) $(libal) -lvorbisfile -lm -lassimp \ 1.23 + -ljpeg -lpng -lz `pkg-config --libs freetype2` 1.24 1.25 ifeq ($(shell uname -s), Darwin) 1.26 + CC = clang 1.27 + CXX = clang++ 1.28 libgl = -framework OpenGL -framework GLUT -lglew 1.29 libal = -framework OpenAL 1.30 else
2.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 2.2 +++ b/prototype/anim/anim.c Sun Oct 07 02:04:00 2012 +0300 2.3 @@ -0,0 +1,394 @@ 2.4 +#include <limits.h> 2.5 +#include <assert.h> 2.6 +#include "anim.h" 2.7 +#include "dynarr.h" 2.8 + 2.9 +int anm_init_node(struct anm_node *node) 2.10 +{ 2.11 + int i, j; 2.12 + static const float defaults[] = { 2.13 + 0.0f, 0.0f, 0.0f, /* default position */ 2.14 + 0.0f, 0.0f, 0.0f, 1.0f, /* default rotation quat */ 2.15 + 1.0f, 1.0f, 1.0f /* default scale factor */ 2.16 + }; 2.17 + 2.18 + memset(node, 0, sizeof *node); 2.19 + 2.20 + for(i=0; i<ANM_NUM_TRACKS; i++) { 2.21 + if(anm_init_track(node->tracks + i) == -1) { 2.22 + for(j=0; j<i; j++) { 2.23 + anm_destroy_track(node->tracks + i); 2.24 + } 2.25 + } 2.26 + anm_set_track_default(node->tracks + i, defaults[i]); 2.27 + } 2.28 + return 0; 2.29 +} 2.30 + 2.31 +void anm_destroy_node(struct anm_node *node) 2.32 +{ 2.33 + int i; 2.34 + free(node->name); 2.35 + 2.36 + for(i=0; i<ANM_NUM_TRACKS; i++) { 2.37 + anm_destroy_track(node->tracks + i); 2.38 + } 2.39 +} 2.40 + 2.41 +void anm_destroy_node_tree(struct anm_node *tree) 2.42 +{ 2.43 + struct anm_node *c, *tmp; 2.44 + 2.45 + if(!tree) return; 2.46 + 2.47 + c = tree->child; 2.48 + while(c) { 2.49 + tmp = c; 2.50 + c = c->next; 2.51 + 2.52 + anm_destroy_node_tree(tmp); 2.53 + } 2.54 + anm_destroy_node(tree); 2.55 +} 2.56 + 2.57 +struct anm_node *anm_create_node(void) 2.58 +{ 2.59 + struct anm_node *n; 2.60 + 2.61 + if((n = malloc(sizeof *n))) { 2.62 + if(anm_init_node(n) == -1) { 2.63 + free(n); 2.64 + return 0; 2.65 + } 2.66 + } 2.67 + return n; 2.68 +} 2.69 + 2.70 +void anm_free_node(struct anm_node *node) 2.71 +{ 2.72 + anm_destroy_node(node); 2.73 + free(node); 2.74 +} 2.75 + 2.76 +void anm_free_node_tree(struct anm_node *tree) 2.77 +{ 2.78 + struct anm_node *c, *tmp; 2.79 + 2.80 + if(!tree) return; 2.81 + 2.82 + c = tree->child; 2.83 + while(c) { 2.84 + tmp = c; 2.85 + c = c->next; 2.86 + 2.87 + anm_free_node_tree(tmp); 2.88 + } 2.89 + 2.90 + anm_free_node(tree); 2.91 +} 2.92 + 2.93 +int anm_set_node_name(struct anm_node *node, const char *name) 2.94 +{ 2.95 + char *str; 2.96 + 2.97 + if(!(str = malloc(strlen(name) + 1))) { 2.98 + return -1; 2.99 + } 2.100 + strcpy(str, name); 2.101 + free(node->name); 2.102 + node->name = str; 2.103 + return 0; 2.104 +} 2.105 + 2.106 +const char *anm_get_node_name(struct anm_node *node) 2.107 +{ 2.108 + return node->name ? node->name : ""; 2.109 +} 2.110 + 2.111 +void anm_set_interpolator(struct anm_node *node, enum anm_interpolator in) 2.112 +{ 2.113 + int i; 2.114 + 2.115 + for(i=0; i<ANM_NUM_TRACKS; i++) { 2.116 + anm_set_track_interpolator(node->tracks + i, in); 2.117 + } 2.118 +} 2.119 + 2.120 +void anm_set_extrapolator(struct anm_node *node, enum anm_extrapolator ex) 2.121 +{ 2.122 + int i; 2.123 + 2.124 + for(i=0; i<ANM_NUM_TRACKS; i++) { 2.125 + anm_set_track_extrapolator(node->tracks + i, ex); 2.126 + } 2.127 +} 2.128 + 2.129 +void anm_link_node(struct anm_node *p, struct anm_node *c) 2.130 +{ 2.131 + c->next = p->child; 2.132 + p->child = c; 2.133 + 2.134 + c->parent = p; 2.135 +} 2.136 + 2.137 +int anm_unlink_node(struct anm_node *p, struct anm_node *c) 2.138 +{ 2.139 + struct anm_node *iter; 2.140 + 2.141 + if(p->child == c) { 2.142 + p->child = c->next; 2.143 + c->next = 0; 2.144 + return 0; 2.145 + } 2.146 + 2.147 + iter = p->child; 2.148 + while(iter->next) { 2.149 + if(iter->next == c) { 2.150 + iter->next = c->next; 2.151 + c->next = 0; 2.152 + return 0; 2.153 + } 2.154 + } 2.155 + return -1; 2.156 +} 2.157 + 2.158 +void anm_set_position(struct anm_node *node, vec3_t pos, anm_time_t tm) 2.159 +{ 2.160 + anm_set_value(node->tracks + ANM_TRACK_POS_X, tm, pos.x); 2.161 + anm_set_value(node->tracks + ANM_TRACK_POS_Y, tm, pos.y); 2.162 + anm_set_value(node->tracks + ANM_TRACK_POS_Z, tm, pos.z); 2.163 +} 2.164 + 2.165 +vec3_t anm_get_node_position(struct anm_node *node, anm_time_t tm) 2.166 +{ 2.167 + vec3_t v; 2.168 + v.x = anm_get_value(node->tracks + ANM_TRACK_POS_X, tm); 2.169 + v.y = anm_get_value(node->tracks + ANM_TRACK_POS_Y, tm); 2.170 + v.z = anm_get_value(node->tracks + ANM_TRACK_POS_Z, tm); 2.171 + return v; 2.172 +} 2.173 + 2.174 +void anm_set_rotation(struct anm_node *node, quat_t rot, anm_time_t tm) 2.175 +{ 2.176 + anm_set_value(node->tracks + ANM_TRACK_ROT_X, tm, rot.x); 2.177 + anm_set_value(node->tracks + ANM_TRACK_ROT_Y, tm, rot.y); 2.178 + anm_set_value(node->tracks + ANM_TRACK_ROT_Z, tm, rot.z); 2.179 + anm_set_value(node->tracks + ANM_TRACK_ROT_W, tm, rot.w); 2.180 +} 2.181 + 2.182 +quat_t anm_get_node_rotation(struct anm_node *node, anm_time_t tm) 2.183 +{ 2.184 + int idx0, idx1, last_idx; 2.185 + anm_time_t tstart, tend; 2.186 + float t, dt; 2.187 + struct anm_track *track_x, *track_y, *track_z, *track_w; 2.188 + quat_t q, q1, q2; 2.189 + 2.190 + track_x = node->tracks + ANM_TRACK_ROT_X; 2.191 + track_y = node->tracks + ANM_TRACK_ROT_Y; 2.192 + track_z = node->tracks + ANM_TRACK_ROT_Z; 2.193 + track_w = node->tracks + ANM_TRACK_ROT_W; 2.194 + 2.195 + if(!track_x->count) { 2.196 + q.x = track_x->def_val; 2.197 + q.y = track_y->def_val; 2.198 + q.z = track_z->def_val; 2.199 + q.w = track_w->def_val; 2.200 + return q; 2.201 + } 2.202 + 2.203 + last_idx = track_x->count - 1; 2.204 + 2.205 + tstart = track_x->keys[0].time; 2.206 + tend = track_x->keys[last_idx].time; 2.207 + tm = anm_remap_time(track_x, tm, tstart, tend); 2.208 + 2.209 + idx0 = anm_get_key_interval(track_x, tm); 2.210 + assert(idx0 >= 0 && idx0 < track_x->count); 2.211 + idx1 = idx0 + 1; 2.212 + 2.213 + dt = (float)(track_x->keys[idx1].time - track_x->keys[idx0].time); 2.214 + t = (float)(tm - track_x->keys[idx0].time) / dt; 2.215 + 2.216 + q1.x = track_x->keys[idx0].val; 2.217 + q1.y = track_y->keys[idx0].val; 2.218 + q1.z = track_z->keys[idx0].val; 2.219 + q1.w = track_w->keys[idx0].val; 2.220 + 2.221 + q2.x = track_x->keys[idx1].val; 2.222 + q2.y = track_y->keys[idx1].val; 2.223 + q2.z = track_z->keys[idx1].val; 2.224 + q2.w = track_w->keys[idx1].val; 2.225 + 2.226 + return quat_slerp(q1, q2, t); 2.227 +} 2.228 + 2.229 +void anm_set_scaling(struct anm_node *node, vec3_t scl, anm_time_t tm) 2.230 +{ 2.231 + anm_set_value(node->tracks + ANM_TRACK_SCL_X, tm, scl.x); 2.232 + anm_set_value(node->tracks + ANM_TRACK_SCL_Y, tm, scl.y); 2.233 + anm_set_value(node->tracks + ANM_TRACK_SCL_Z, tm, scl.z); 2.234 +} 2.235 + 2.236 +vec3_t anm_get_node_scaling(struct anm_node *node, anm_time_t tm) 2.237 +{ 2.238 + vec3_t v; 2.239 + v.x = anm_get_value(node->tracks + ANM_TRACK_SCL_X, tm); 2.240 + v.y = anm_get_value(node->tracks + ANM_TRACK_SCL_Y, tm); 2.241 + v.z = anm_get_value(node->tracks + ANM_TRACK_SCL_Z, tm); 2.242 + return v; 2.243 +} 2.244 + 2.245 + 2.246 +vec3_t anm_get_position(struct anm_node *node, anm_time_t tm) 2.247 +{ 2.248 + mat4_t xform; 2.249 + vec3_t pos = {0.0, 0.0, 0.0}; 2.250 + 2.251 + if(!node->parent) { 2.252 + return anm_get_node_position(node, tm); 2.253 + } 2.254 + 2.255 + anm_get_matrix(node, xform, tm); 2.256 + return v3_transform(pos, xform); 2.257 +} 2.258 + 2.259 +quat_t anm_get_rotation(struct anm_node *node, anm_time_t tm) 2.260 +{ 2.261 + quat_t rot, prot; 2.262 + rot = anm_get_node_rotation(node, tm); 2.263 + 2.264 + if(!node->parent) { 2.265 + return rot; 2.266 + } 2.267 + 2.268 + prot = anm_get_rotation(node->parent, tm); 2.269 + return quat_mul(prot, rot); 2.270 +} 2.271 + 2.272 +vec3_t anm_get_scaling(struct anm_node *node, anm_time_t tm) 2.273 +{ 2.274 + vec3_t s, ps; 2.275 + s = anm_get_node_scaling(node, tm); 2.276 + 2.277 + if(!node->parent) { 2.278 + return s; 2.279 + } 2.280 + 2.281 + ps = anm_get_scaling(node->parent, tm); 2.282 + return v3_mul(s, ps); 2.283 +} 2.284 + 2.285 +void anm_set_pivot(struct anm_node *node, vec3_t piv) 2.286 +{ 2.287 + node->pivot = piv; 2.288 +} 2.289 + 2.290 +vec3_t anm_get_pivot(struct anm_node *node) 2.291 +{ 2.292 + return node->pivot; 2.293 +} 2.294 + 2.295 +void anm_get_matrix(struct anm_node *node, mat4_t mat, anm_time_t tm) 2.296 +{ 2.297 +#ifdef ANIM_THREAD_SAFE 2.298 + /* XXX we're holding the mutex for way too anm_time_t... but it looks like the 2.299 + * alternative would be to lock/unlock twice which might be worse. 2.300 + */ 2.301 + pthread_mutex_lock(node->cache_mutex); 2.302 +#endif 2.303 + 2.304 + if(node->cache_time != tm) { 2.305 + mat4_t tmat, rmat, smat, pivmat, neg_pivmat; 2.306 + vec3_t pos, scale; 2.307 + quat_t rot; 2.308 + 2.309 + m4_identity(tmat); 2.310 + /*no need to m4_identity(rmat); quat_to_mat4 sets this properly */ 2.311 + m4_identity(smat); 2.312 + m4_identity(pivmat); 2.313 + m4_identity(neg_pivmat); 2.314 + 2.315 + pos = anm_get_node_position(node, tm); 2.316 + rot = anm_get_node_rotation(node, tm); 2.317 + scale = anm_get_node_scaling(node, tm); 2.318 + 2.319 + m4_translate(pivmat, node->pivot.x, node->pivot.y, node->pivot.z); 2.320 + m4_translate(neg_pivmat, -node->pivot.x, -node->pivot.y, -node->pivot.z); 2.321 + 2.322 + m4_translate(tmat, pos.x, pos.y, pos.z); 2.323 + quat_to_mat4(rmat, rot); 2.324 + m4_translate(smat, scale.x, scale.y, scale.z); 2.325 + 2.326 + /* ok this would look nicer in C++ */ 2.327 + m4_mult(node->cache_matrix, pivmat, tmat); 2.328 + m4_mult(node->cache_matrix, node->cache_matrix, rmat); 2.329 + m4_mult(node->cache_matrix, node->cache_matrix, smat); 2.330 + m4_mult(node->cache_matrix, node->cache_matrix, neg_pivmat); 2.331 + 2.332 + if(node->parent) { 2.333 + mat4_t parent_mat; 2.334 + 2.335 + anm_get_matrix(node->parent, mat, tm); 2.336 + m4_mult(node->cache_matrix, parent_mat, node->cache_matrix); 2.337 + } 2.338 + node->cache_time = tm; 2.339 + } 2.340 + m4_copy(mat, node->cache_matrix); 2.341 + 2.342 +#ifdef ANIM_THREAD_SAFE 2.343 + pthread_mutex_unlock(node->cache_mutex); 2.344 +#endif 2.345 +} 2.346 + 2.347 +anm_time_t anm_get_start_time(struct anm_node *node) 2.348 +{ 2.349 + int i; 2.350 + struct anm_node *c; 2.351 + anm_time_t res = LONG_MAX; 2.352 + 2.353 + for(i=0; i<ANM_NUM_TRACKS; i++) { 2.354 + if(node->tracks[i].count) { 2.355 + anm_time_t tm = node->tracks[i].keys[0].time; 2.356 + if(tm < res) { 2.357 + res = tm; 2.358 + } 2.359 + } 2.360 + } 2.361 + 2.362 + c = node->child; 2.363 + while(c) { 2.364 + anm_time_t tm = anm_get_start_time(c); 2.365 + if(tm < res) { 2.366 + res = tm; 2.367 + } 2.368 + c = c->next; 2.369 + } 2.370 + return res; 2.371 +} 2.372 + 2.373 +anm_time_t anm_get_end_time(struct anm_node *node) 2.374 +{ 2.375 + int i; 2.376 + struct anm_node *c; 2.377 + anm_time_t res = LONG_MIN; 2.378 + 2.379 + for(i=0; i<ANM_NUM_TRACKS; i++) { 2.380 + if(node->tracks[i].count) { 2.381 + anm_time_t tm = node->tracks[i].keys[node->tracks[i].count - 1].time; 2.382 + if(tm > res) { 2.383 + res = tm; 2.384 + } 2.385 + } 2.386 + } 2.387 + 2.388 + c = node->child; 2.389 + while(c) { 2.390 + anm_time_t tm = anm_get_end_time(c); 2.391 + if(tm > res) { 2.392 + res = tm; 2.393 + } 2.394 + c = c->next; 2.395 + } 2.396 + return res; 2.397 +}
3.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 3.2 +++ b/prototype/anim/anim.h Sun Oct 07 02:04:00 2012 +0300 3.3 @@ -0,0 +1,99 @@ 3.4 +#ifndef LIBANIM_H_ 3.5 +#define LIBANIM_H_ 3.6 + 3.7 +#include "config.h" 3.8 + 3.9 +#ifdef ANIM_THREAD_SAFE 3.10 +#include <pthread.h> 3.11 +#endif 3.12 + 3.13 +#include <vmath/vmath.h> 3.14 +#include "track.h" 3.15 + 3.16 +enum { 3.17 + ANM_TRACK_POS_X, 3.18 + ANM_TRACK_POS_Y, 3.19 + ANM_TRACK_POS_Z, 3.20 + 3.21 + ANM_TRACK_ROT_X, 3.22 + ANM_TRACK_ROT_Y, 3.23 + ANM_TRACK_ROT_Z, 3.24 + ANM_TRACK_ROT_W, 3.25 + 3.26 + ANM_TRACK_SCL_X, 3.27 + ANM_TRACK_SCL_Y, 3.28 + ANM_TRACK_SCL_Z, 3.29 + 3.30 + ANM_NUM_TRACKS 3.31 +}; 3.32 + 3.33 +struct anm_node { 3.34 + char *name; 3.35 + 3.36 + struct anm_track tracks[ANM_NUM_TRACKS]; 3.37 + vec3_t pivot; 3.38 + 3.39 + /* matrix cache */ 3.40 + mat4_t cache_matrix; 3.41 + anm_time_t cache_time; 3.42 +#ifdef ANIM_THREAD_SAFE 3.43 + pthread_mutex_t cache_mutex; 3.44 +#endif 3.45 + 3.46 + struct anm_node *parent; 3.47 + struct anm_node *child; 3.48 + struct anm_node *next; 3.49 +}; 3.50 + 3.51 + 3.52 +/* node constructor and destructor */ 3.53 +int anm_init_node(struct anm_node *node); 3.54 +void anm_destroy_node(struct anm_node *node); 3.55 + 3.56 +/* recursively destroy an animation node tree */ 3.57 +void anm_destroy_node_tree(struct anm_node *tree); 3.58 + 3.59 +/* helper functions to allocate/construct and destroy/free with 3.60 + * a single call. They call anm_init_node and anm_destroy_node 3.61 + * internally. 3.62 + */ 3.63 +struct anm_node *anm_create_node(void); 3.64 +void anm_free_node(struct anm_node *node); 3.65 + 3.66 +/* recursively destroy and free the nodes of a node tree */ 3.67 +void anm_free_node_tree(struct anm_node *tree); 3.68 + 3.69 +int anm_set_node_name(struct anm_node *node, const char *name); 3.70 +const char *anm_get_node_name(struct anm_node *node); 3.71 + 3.72 +void anm_set_interpolator(struct anm_node *node, enum anm_interpolator in); 3.73 +void anm_set_extrapolator(struct anm_node *node, enum anm_extrapolator ex); 3.74 + 3.75 +/* link and unlink nodes with parent/child relations */ 3.76 +void anm_link_node(struct anm_node *parent, struct anm_node *child); 3.77 +int anm_unlink_node(struct anm_node *parent, struct anm_node *child); 3.78 + 3.79 +void anm_set_position(struct anm_node *node, vec3_t pos, anm_time_t tm); 3.80 +vec3_t anm_get_node_position(struct anm_node *node, anm_time_t tm); 3.81 + 3.82 +void anm_set_rotation(struct anm_node *node, quat_t rot, anm_time_t tm); 3.83 +quat_t anm_get_node_rotation(struct anm_node *node, anm_time_t tm); 3.84 + 3.85 +void anm_set_scaling(struct anm_node *node, vec3_t scl, anm_time_t tm); 3.86 +vec3_t anm_get_node_scaling(struct anm_node *node, anm_time_t tm); 3.87 + 3.88 +/* these three return the full p/r/s taking hierarchy into account */ 3.89 +vec3_t anm_get_position(struct anm_node *node, anm_time_t tm); 3.90 +quat_t anm_get_rotation(struct anm_node *node, anm_time_t tm); 3.91 +vec3_t anm_get_scaling(struct anm_node *node, anm_time_t tm); 3.92 + 3.93 +void anm_set_pivot(struct anm_node *node, vec3_t pivot); 3.94 +vec3_t anm_get_pivot(struct anm_node *node); 3.95 + 3.96 +void anm_get_matrix(struct anm_node *node, mat4_t mat, anm_time_t tm); 3.97 + 3.98 +/* those return the start and end times of the whole tree */ 3.99 +anm_time_t anm_get_start_time(struct anm_node *node); 3.100 +anm_time_t anm_get_end_time(struct anm_node *node); 3.101 + 3.102 +#endif /* LIBANIM_H_ */
4.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 4.2 +++ b/prototype/anim/config.h Sun Oct 07 02:04:00 2012 +0300 4.3 @@ -0,0 +1,6 @@ 4.4 +#ifndef ANIM_CONFIG_H_ 4.5 +#define ANIM_CONFIG_H_ 4.6 + 4.7 +#undef ANIM_THREAD_SAFE 4.8 + 4.9 +#endif /* ANIM_CONFIG_H_ */
5.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 5.2 +++ b/prototype/anim/dynarr.c Sun Oct 07 02:04:00 2012 +0300 5.3 @@ -0,0 +1,122 @@ 5.4 +#include <stdio.h> 5.5 +#include <stdlib.h> 5.6 +#include <string.h> 5.7 +#include "dynarr.h" 5.8 + 5.9 +/* The array descriptor keeps auxilliary information needed to manipulate 5.10 + * the dynamic array. It's allocated adjacent to the array buffer. 5.11 + */ 5.12 +struct arrdesc { 5.13 + int nelem, szelem; 5.14 + int max_elem; 5.15 + int bufsz; /* not including the descriptor */ 5.16 +}; 5.17 + 5.18 +#define DESC(x) ((struct arrdesc*)((char*)(x) - sizeof(struct arrdesc))) 5.19 + 5.20 +void *dynarr_alloc(int elem, int szelem) 5.21 +{ 5.22 + struct arrdesc *desc; 5.23 + 5.24 + if(!(desc = malloc(elem * szelem + sizeof *desc))) { 5.25 + return 0; 5.26 + } 5.27 + desc->nelem = desc->max_elem = elem; 5.28 + desc->szelem = szelem; 5.29 + desc->bufsz = elem * szelem; 5.30 + return (char*)desc + sizeof *desc; 5.31 +} 5.32 + 5.33 +void dynarr_free(void *da) 5.34 +{ 5.35 + if(da) { 5.36 + free(DESC(da)); 5.37 + } 5.38 +} 5.39 + 5.40 +void *dynarr_resize(void *da, int elem) 5.41 +{ 5.42 + int newsz; 5.43 + void *tmp; 5.44 + struct arrdesc *desc; 5.45 + 5.46 + if(!da) return 0; 5.47 + desc = DESC(da); 5.48 + 5.49 + newsz = desc->szelem * elem; 5.50 + 5.51 + if(!(tmp = realloc(desc, newsz + sizeof *desc))) { 5.52 + return 0; 5.53 + } 5.54 + desc = tmp; 5.55 + 5.56 + desc->nelem = desc->max_elem = elem; 5.57 + desc->bufsz = newsz; 5.58 + return (char*)desc + sizeof *desc; 5.59 +} 5.60 + 5.61 +int dynarr_empty(void *da) 5.62 +{ 5.63 + return DESC(da)->nelem ? 0 : 1; 5.64 +} 5.65 + 5.66 +int dynarr_size(void *da) 5.67 +{ 5.68 + return DESC(da)->nelem; 5.69 +} 5.70 + 5.71 + 5.72 +/* stack semantics */ 5.73 +void *dynarr_push(void *da, void *item) 5.74 +{ 5.75 + struct arrdesc *desc; 5.76 + int nelem; 5.77 + 5.78 + desc = DESC(da); 5.79 + nelem = desc->nelem; 5.80 + 5.81 + if(nelem >= desc->max_elem) { 5.82 + /* need to resize */ 5.83 + struct arrdesc *tmp; 5.84 + int newsz = desc->max_elem ? desc->max_elem * 2 : 1; 5.85 + 5.86 + if(!(tmp = dynarr_resize(da, newsz))) { 5.87 + fprintf(stderr, "failed to resize\n"); 5.88 + return da; 5.89 + } 5.90 + da = tmp; 5.91 + desc = DESC(da); 5.92 + desc->nelem = nelem; 5.93 + } 5.94 + 5.95 + memcpy((char*)da + desc->nelem++ * desc->szelem, item, desc->szelem); 5.96 + return da; 5.97 +} 5.98 + 5.99 +void *dynarr_pop(void *da) 5.100 +{ 5.101 + struct arrdesc *desc; 5.102 + int nelem; 5.103 + 5.104 + desc = DESC(da); 5.105 + nelem = desc->nelem; 5.106 + 5.107 + if(!nelem) return da; 5.108 + 5.109 + if(nelem <= desc->max_elem / 3) { 5.110 + /* reclaim space */ 5.111 + struct arrdesc *tmp; 5.112 + int newsz = desc->max_elem / 2; 5.113 + 5.114 + if(!(tmp = dynarr_resize(da, newsz))) { 5.115 + fprintf(stderr, "failed to resize\n"); 5.116 + return da; 5.117 + } 5.118 + da = tmp; 5.119 + desc = DESC(da); 5.120 + desc->nelem = nelem; 5.121 + } 5.122 + desc->nelem--; 5.123 + 5.124 + return da; 5.125 +}
6.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 6.2 +++ b/prototype/anim/dynarr.h Sun Oct 07 02:04:00 2012 +0300 6.3 @@ -0,0 +1,16 @@ 6.4 +#ifndef DYNARR_H_ 6.5 +#define DYNARR_H_ 6.6 + 6.7 +void *dynarr_alloc(int elem, int szelem); 6.8 +void dynarr_free(void *da); 6.9 +void *dynarr_resize(void *da, int elem); 6.10 + 6.11 +int dynarr_empty(void *da); 6.12 +int dynarr_size(void *da); 6.13 + 6.14 +/* stack semantics */ 6.15 +void *dynarr_push(void *da, void *item); 6.16 +void *dynarr_pop(void *da); 6.17 + 6.18 + 6.19 +#endif /* DYNARR_H_ */
7.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 7.2 +++ b/prototype/anim/track.c Sun Oct 07 02:04:00 2012 +0300 7.3 @@ -0,0 +1,272 @@ 7.4 +#include <stdlib.h> 7.5 +#include <string.h> 7.6 +#include <assert.h> 7.7 +#include "track.h" 7.8 +#include "dynarr.h" 7.9 + 7.10 +static int keycmp(const void *a, const void *b); 7.11 +static int find_prev_key(struct anm_keyframe *arr, int start, int end, anm_time_t tm); 7.12 + 7.13 +static float interp_step(float v0, float v1, float v2, float v3, float t); 7.14 +static float interp_linear(float v0, float v1, float v2, float v3, float t); 7.15 +static float interp_cubic(float v0, float v1, float v2, float v3, float t); 7.16 + 7.17 +static anm_time_t remap_extend(anm_time_t tm, anm_time_t start, anm_time_t end); 7.18 +static anm_time_t remap_clamp(anm_time_t tm, anm_time_t start, anm_time_t end); 7.19 +static anm_time_t remap_repeat(anm_time_t tm, anm_time_t start, anm_time_t end); 7.20 + 7.21 +/* XXX keep this in sync with enum anm_interpolator at track.h */ 7.22 +static float (*interp[])(float, float, float, float, float) = { 7.23 + interp_step, 7.24 + interp_linear, 7.25 + interp_cubic, 7.26 + 0 7.27 +}; 7.28 + 7.29 +/* XXX keep this in sync with enum anm_extrapolator at track.h */ 7.30 +static anm_time_t (*remap_time[])(anm_time_t, anm_time_t, anm_time_t) = { 7.31 + remap_extend, 7.32 + remap_clamp, 7.33 + remap_repeat, 7.34 + 0 7.35 +}; 7.36 + 7.37 +int anm_init_track(struct anm_track *track) 7.38 +{ 7.39 + memset(track, 0, sizeof *track); 7.40 + 7.41 + if(!(track->keys = dynarr_alloc(0, sizeof *track->keys))) { 7.42 + return -1; 7.43 + } 7.44 + track->interp = ANM_INTERP_LINEAR; 7.45 + track->extrap = ANM_EXTRAP_CLAMP; 7.46 + return 0; 7.47 +} 7.48 + 7.49 +void anm_destroy_track(struct anm_track *track) 7.50 +{ 7.51 + dynarr_free(track->keys); 7.52 +} 7.53 + 7.54 +struct anm_track *anm_create_track(void) 7.55 +{ 7.56 + struct anm_track *track; 7.57 + 7.58 + if((track = malloc(sizeof *track))) { 7.59 + if(anm_init_track(track) == -1) { 7.60 + free(track); 7.61 + return 0; 7.62 + } 7.63 + } 7.64 + return track; 7.65 +} 7.66 + 7.67 +void anm_free_track(struct anm_track *track) 7.68 +{ 7.69 + anm_destroy_track(track); 7.70 + free(track); 7.71 +} 7.72 + 7.73 +int anm_set_track_name(struct anm_track *track, const char *name) 7.74 +{ 7.75 + char *tmp; 7.76 + 7.77 + if(!(tmp = malloc(strlen(name) + 1))) { 7.78 + return -1; 7.79 + } 7.80 + free(track->name); 7.81 + track->name = tmp; 7.82 + return 0; 7.83 +} 7.84 + 7.85 +const char *anm_get_track_name(struct anm_track *track) 7.86 +{ 7.87 + return track->name; 7.88 +} 7.89 + 7.90 +void anm_set_track_interpolator(struct anm_track *track, enum anm_interpolator in) 7.91 +{ 7.92 + track->interp = in; 7.93 +} 7.94 + 7.95 +void anm_set_track_extrapolator(struct anm_track *track, enum anm_extrapolator ex) 7.96 +{ 7.97 + track->extrap = ex; 7.98 +} 7.99 + 7.100 +anm_time_t anm_remap_time(struct anm_track *track, anm_time_t tm, anm_time_t start, anm_time_t end) 7.101 +{ 7.102 + return remap_time[track->extrap](tm, start, end); 7.103 +} 7.104 + 7.105 +void anm_set_track_default(struct anm_track *track, float def) 7.106 +{ 7.107 + track->def_val = def; 7.108 +} 7.109 + 7.110 +int anm_set_keyframe(struct anm_track *track, struct anm_keyframe *key) 7.111 +{ 7.112 + int idx = anm_get_key_interval(track, key->time); 7.113 + 7.114 + /* if we got a valid keyframe index, compare them... */ 7.115 + if(idx >= 0 && idx < track->count && keycmp(key, track->keys + idx) == 0) { 7.116 + /* ... it's the same key, just update the value */ 7.117 + track->keys[idx].val = key->val; 7.118 + } else { 7.119 + /* ... it's a new key, add it and re-sort them */ 7.120 + void *tmp; 7.121 + if(!(tmp = dynarr_push(track->keys, key))) { 7.122 + return -1; 7.123 + } 7.124 + track->keys = tmp; 7.125 + /* TODO lazy qsort */ 7.126 + qsort(track->keys, ++track->count, sizeof *track->keys, keycmp); 7.127 + } 7.128 + return 0; 7.129 +} 7.130 + 7.131 +static int keycmp(const void *a, const void *b) 7.132 +{ 7.133 + return ((struct anm_keyframe*)a)->time - ((struct anm_keyframe*)b)->time; 7.134 +} 7.135 + 7.136 +struct anm_keyframe *anm_get_keyframe(struct anm_track *track, int idx) 7.137 +{ 7.138 + if(idx < 0 || idx >= track->count) { 7.139 + return 0; 7.140 + } 7.141 + return track->keys + idx; 7.142 +} 7.143 + 7.144 +int anm_get_key_interval(struct anm_track *track, anm_time_t tm) 7.145 +{ 7.146 + int last; 7.147 + 7.148 + if(!track->count || tm < track->keys[0].time) { 7.149 + return -1; 7.150 + } 7.151 + 7.152 + last = track->count - 1; 7.153 + if(tm > track->keys[last].time) { 7.154 + return last; 7.155 + } 7.156 + 7.157 + return find_prev_key(track->keys, 0, last, tm); 7.158 +} 7.159 + 7.160 +static int find_prev_key(struct anm_keyframe *arr, int start, int end, anm_time_t tm) 7.161 +{ 7.162 + int mid; 7.163 + 7.164 + if(end - start <= 1) { 7.165 + return start; 7.166 + } 7.167 + 7.168 + mid = (start + end) / 2; 7.169 + if(tm < arr[mid].time) { 7.170 + return find_prev_key(arr, start, mid, tm); 7.171 + } 7.172 + if(tm > arr[mid].time) { 7.173 + return find_prev_key(arr, mid, end, tm); 7.174 + } 7.175 + return mid; 7.176 +} 7.177 + 7.178 +int anm_set_value(struct anm_track *track, anm_time_t tm, float val) 7.179 +{ 7.180 + struct anm_keyframe key; 7.181 + key.time = tm; 7.182 + key.val = val; 7.183 + 7.184 + return anm_set_keyframe(track, &key); 7.185 +} 7.186 + 7.187 +float anm_get_value(struct anm_track *track, anm_time_t tm) 7.188 +{ 7.189 + int idx0, idx1, last_idx; 7.190 + anm_time_t tstart, tend; 7.191 + float t, dt; 7.192 + float v0, v1, v2, v3; 7.193 + 7.194 + if(!track->count) { 7.195 + return track->def_val; 7.196 + } 7.197 + 7.198 + last_idx = track->count - 1; 7.199 + 7.200 + tstart = track->keys[0].time; 7.201 + tend = track->keys[last_idx].time; 7.202 + 7.203 + if(tstart == tend) { 7.204 + return track->keys[0].val; 7.205 + } 7.206 + 7.207 + tm = remap_time[track->extrap](tm, tstart, tend); 7.208 + 7.209 + idx0 = anm_get_key_interval(track, tm); 7.210 + assert(idx0 >= 0 && idx0 < track->count); 7.211 + idx1 = idx0 + 1; 7.212 + 7.213 + if(idx0 == last_idx) { 7.214 + return track->keys[idx0].val; 7.215 + } 7.216 + 7.217 + dt = (float)(track->keys[idx1].time - track->keys[idx0].time); 7.218 + t = (float)(tm - track->keys[idx0].time) / dt; 7.219 + 7.220 + v1 = track->keys[idx0].val; 7.221 + v2 = track->keys[idx1].val; 7.222 + 7.223 + /* get the neigboring values to allow for cubic interpolation */ 7.224 + v0 = idx0 > 0 ? track->keys[idx0 - 1].val : v1; 7.225 + v3 = idx1 < last_idx ? track->keys[idx1 + 1].val : v2; 7.226 + 7.227 + return interp[track->interp](v0, v1, v2, v3, t); 7.228 +} 7.229 + 7.230 + 7.231 +static float interp_step(float v0, float v1, float v2, float v3, float t) 7.232 +{ 7.233 + return v1; 7.234 +} 7.235 + 7.236 +static float interp_linear(float v0, float v1, float v2, float v3, float t) 7.237 +{ 7.238 + return v1 + (v2 - v1) * t; 7.239 +} 7.240 + 7.241 +static float interp_cubic(float a, float b, float c, float d, float t) 7.242 +{ 7.243 + float x, y, z, w; 7.244 + float tsq = t * t; 7.245 + 7.246 + x = -a + 3.0 * b - 3.0 * c + d; 7.247 + y = 2.0 * a - 5.0 * b + 4.0 * c - d; 7.248 + z = c - a; 7.249 + w = 2.0 * b; 7.250 + 7.251 + return 0.5 * (x * tsq * t + y * tsq + z * t + w); 7.252 +} 7.253 + 7.254 +static anm_time_t remap_extend(anm_time_t tm, anm_time_t start, anm_time_t end) 7.255 +{ 7.256 + return remap_repeat(tm, start, end); 7.257 +} 7.258 + 7.259 +static anm_time_t remap_clamp(anm_time_t tm, anm_time_t start, anm_time_t end) 7.260 +{ 7.261 + return tm < start ? start : (tm >= end ? end - 1 : tm); 7.262 +} 7.263 + 7.264 +static anm_time_t remap_repeat(anm_time_t tm, anm_time_t start, anm_time_t end) 7.265 +{ 7.266 + anm_time_t interv = end - start; 7.267 + 7.268 + if(tm < start) { 7.269 + while(tm < start) { 7.270 + tm += interv; 7.271 + } 7.272 + return tm; 7.273 + } 7.274 + return (tm - start) % interv + start; 7.275 +}
8.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 8.2 +++ b/prototype/anim/track.h Sun Oct 07 02:04:00 2012 +0300 8.3 @@ -0,0 +1,88 @@ 8.4 +/* An animation track defines the values of a single scalar over time 8.5 + * and supports various interpolation and extrapolation modes. 8.6 + */ 8.7 +#ifndef LIBANIM_TRACK_H_ 8.8 +#define LIBANIM_TRACK_H_ 8.9 + 8.10 +#include <limits.h> 8.11 +#include "config.h" 8.12 + 8.13 +enum anm_interpolator { 8.14 + ANM_INTERP_STEP, 8.15 + ANM_INTERP_LINEAR, 8.16 + ANM_INTERP_CUBIC 8.17 +}; 8.18 + 8.19 +enum anm_extrapolator { 8.20 + ANM_EXTRAP_EXTEND, /* extend to infinity */ 8.21 + ANM_EXTRAP_CLAMP, /* clamp to last value */ 8.22 + ANM_EXTRAP_REPEAT /* repeat motion */ 8.23 +}; 8.24 + 8.25 +typedef long anm_time_t; 8.26 +#define ANM_TIME_INVAL LONG_MIN 8.27 + 8.28 +#define ANM_SEC2TM(x) ((anm_time_t)((x) * 1000)) 8.29 +#define ANM_MSEC2TM(x) ((anm_time_t)(x)) 8.30 +#define ANM_TM2SEC(x) ((x) / 1000.0) 8.31 +#define ANM_TM2MSEC(x) (x) 8.32 + 8.33 +struct anm_keyframe { 8.34 + anm_time_t time; 8.35 + float val; 8.36 +}; 8.37 + 8.38 +struct anm_track { 8.39 + char *name; 8.40 + int count; 8.41 + struct anm_keyframe *keys; 8.42 + 8.43 + float def_val; 8.44 + 8.45 + enum anm_interpolator interp; 8.46 + enum anm_extrapolator extrap; 8.47 +}; 8.48 + 8.49 +/* track constructor and destructor */ 8.50 +int anm_init_track(struct anm_track *track); 8.51 +void anm_destroy_track(struct anm_track *track); 8.52 + 8.53 +/* helper functions that use anm_init_track and anm_destroy_track internally */ 8.54 +struct anm_track *anm_create_track(void); 8.55 +void anm_free_track(struct anm_track *track); 8.56 + 8.57 +int anm_set_track_name(struct anm_track *track, const char *name); 8.58 +const char *anm_get_track_name(struct anm_track *track); 8.59 + 8.60 +void anm_set_track_interpolator(struct anm_track *track, enum anm_interpolator in); 8.61 +void anm_set_track_extrapolator(struct anm_track *track, enum anm_extrapolator ex); 8.62 + 8.63 +anm_time_t anm_remap_time(struct anm_track *track, anm_time_t tm, anm_time_t start, anm_time_t end); 8.64 + 8.65 +void anm_set_track_default(struct anm_track *track, float def); 8.66 + 8.67 +/* set or update a keyframe */ 8.68 +int anm_set_keyframe(struct anm_track *track, struct anm_keyframe *key); 8.69 + 8.70 +/* get the idx-th keyframe, returns null if it doesn't exist */ 8.71 +struct anm_keyframe *anm_get_keyframe(struct anm_track *track, int idx); 8.72 + 8.73 +/* Finds the 0-based index of the intra-keyframe interval which corresponds 8.74 + * to the specified time. If the time falls exactly onto the N-th keyframe 8.75 + * the function returns N. 8.76 + * 8.77 + * Special cases: 8.78 + * - if the time is before the first keyframe -1 is returned. 8.79 + * - if the time is after the last keyframe, the index of the last keyframe 8.80 + * is returned. 8.81 + */ 8.82 +int anm_get_key_interval(struct anm_track *track, anm_time_t tm); 8.83 + 8.84 +int anm_set_value(struct anm_track *track, anm_time_t tm, float val); 8.85 + 8.86 +/* evaluates and returns the value of the track for a particular time */ 8.87 +float anm_get_value(struct anm_track *track, anm_time_t tm); 8.88 + 8.89 + 8.90 + 8.91 +#endif /* LIBANIM_TRACK_H_ */
9.1 --- a/prototype/data/fire.psys Tue Oct 02 13:42:18 2012 +0300 9.2 +++ b/prototype/data/fire.psys Sun Oct 07 02:04:00 2012 +0300 9.3 @@ -11,13 +11,13 @@ 9.4 # center ~ range. If the range is missing, it's assumed to be 0. 9.5 9.6 texture = "fire_particle.png" 9.7 -rate = 50 9.8 +rate = 40 9.9 life = 0.9 ~ 0.1 9.10 grav = [0 0.3 0] 9.11 spawn_range = 0.025 9.12 9.13 -size(0) = 0.2 9.14 -size(1s) = 0.075 9.15 +size(0) = 0.25 9.16 +size(1s) = 0.08 9.17 9.18 pcolor(0) = [1.0 0.7 0.1] 9.19 pcolor(1s) = [1.0 0.27 0.15]
10.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 10.2 +++ b/prototype/imago2/conv.c Sun Oct 07 02:04:00 2012 +0300 10.3 @@ -0,0 +1,251 @@ 10.4 +/* 10.5 +libimago - a multi-format image file input/output library. 10.6 +Copyright (C) 2010 John Tsiombikas <nuclear@member.fsf.org> 10.7 + 10.8 +This program is free software: you can redistribute it and/or modify 10.9 +it under the terms of the GNU Lesser General Public License as published 10.10 +by the Free Software Foundation, either version 3 of the License, or 10.11 +(at your option) any later version. 10.12 + 10.13 +This program is distributed in the hope that it will be useful, 10.14 +but WITHOUT ANY WARRANTY; without even the implied warranty of 10.15 +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10.16 +GNU Lesser General Public License for more details. 10.17 + 10.18 +You should have received a copy of the GNU Lesser General Public License 10.19 +along with this program. If not, see <http://www.gnu.org/licenses/>. 10.20 +*/ 10.21 +#include <string.h> 10.22 +#include "imago2.h" 10.23 + 10.24 +/* pixel-format conversions are sub-optimal at the moment to avoid 10.25 + * writing a lot of code. optimize at some point ? 10.26 + */ 10.27 + 10.28 +#define CLAMP(x, a, b) ((x) < (a) ? (a) : ((x) > (b) ? (b) : (x))) 10.29 + 10.30 +struct pixel { 10.31 + float r, g, b, a; 10.32 +}; 10.33 + 10.34 +static void unpack_grey8(struct pixel *unp, void *pptr, int count); 10.35 +static void unpack_rgb24(struct pixel *unp, void *pptr, int count); 10.36 +static void unpack_rgba32(struct pixel *unp, void *pptr, int count); 10.37 +static void unpack_greyf(struct pixel *unp, void *pptr, int count); 10.38 +static void unpack_rgbf(struct pixel *unp, void *pptr, int count); 10.39 +static void unpack_rgbaf(struct pixel *unp, void *pptr, int count); 10.40 + 10.41 +static void pack_grey8(void *pptr, struct pixel *unp, int count); 10.42 +static void pack_rgb24(void *pptr, struct pixel *unp, int count); 10.43 +static void pack_rgba32(void *pptr, struct pixel *unp, int count); 10.44 +static void pack_greyf(void *pptr, struct pixel *unp, int count); 10.45 +static void pack_rgbf(void *pptr, struct pixel *unp, int count); 10.46 +static void pack_rgbaf(void *pptr, struct pixel *unp, int count); 10.47 + 10.48 +/* XXX keep in sync with enum img_fmt at imago2.h */ 10.49 +static void (*unpack[])(struct pixel*, void*, int) = { 10.50 + unpack_grey8, 10.51 + unpack_rgb24, 10.52 + unpack_rgba32, 10.53 + unpack_greyf, 10.54 + unpack_rgbf, 10.55 + unpack_rgbaf 10.56 +}; 10.57 + 10.58 +/* XXX keep in sync with enum img_fmt at imago2.h */ 10.59 +static void (*pack[])(void*, struct pixel*, int) = { 10.60 + pack_grey8, 10.61 + pack_rgb24, 10.62 + pack_rgba32, 10.63 + pack_greyf, 10.64 + pack_rgbf, 10.65 + pack_rgbaf 10.66 +}; 10.67 + 10.68 + 10.69 +int img_convert(struct img_pixmap *img, enum img_fmt tofmt) 10.70 +{ 10.71 + struct pixel pbuf[8]; 10.72 + int bufsz = (img->width & 7) == 0 ? 8 : ((img->width & 3) == 0 ? 4 : 1); 10.73 + int i, num_pix = img->width * img->height; 10.74 + int num_iter = num_pix / bufsz; 10.75 + char *sptr, *dptr; 10.76 + struct img_pixmap nimg; 10.77 + 10.78 + if(img->fmt == tofmt) { 10.79 + return 0; /* nothing to do */ 10.80 + } 10.81 + 10.82 + img_init(&nimg); 10.83 + if(img_set_pixels(&nimg, img->width, img->height, tofmt, 0) == -1) { 10.84 + img_destroy(&nimg); 10.85 + return -1; 10.86 + } 10.87 + 10.88 + sptr = img->pixels; 10.89 + dptr = nimg.pixels; 10.90 + 10.91 + for(i=0; i<num_iter; i++) { 10.92 + unpack[img->fmt](pbuf, sptr, bufsz); 10.93 + pack[tofmt](dptr, pbuf, bufsz); 10.94 + 10.95 + sptr += bufsz * img->pixelsz; 10.96 + dptr += bufsz * nimg.pixelsz; 10.97 + } 10.98 + 10.99 + img_copy(img, &nimg); 10.100 + img_destroy(&nimg); 10.101 + return 0; 10.102 +} 10.103 + 10.104 +/* the following functions *could* benefit from SIMD */ 10.105 + 10.106 +static void unpack_grey8(struct pixel *unp, void *pptr, int count) 10.107 +{ 10.108 + int i; 10.109 + unsigned char *pix = pptr; 10.110 + 10.111 + for(i=0; i<count; i++) { 10.112 + unp->r = unp->g = unp->b = (float)*pix++ / 255.0; 10.113 + unp->a = 1.0; 10.114 + unp++; 10.115 + } 10.116 +} 10.117 + 10.118 +static void unpack_rgb24(struct pixel *unp, void *pptr, int count) 10.119 +{ 10.120 + int i; 10.121 + unsigned char *pix = pptr; 10.122 + 10.123 + for(i=0; i<count; i++) { 10.124 + unp->r = (float)*pix++ / 255.0; 10.125 + unp->g = (float)*pix++ / 255.0; 10.126 + unp->b = (float)*pix++ / 255.0; 10.127 + unp->a = 1.0; 10.128 + unp++; 10.129 + } 10.130 +} 10.131 + 10.132 +static void unpack_rgba32(struct pixel *unp, void *pptr, int count) 10.133 +{ 10.134 + memcpy(unp, pptr, count * sizeof *unp); 10.135 +} 10.136 + 10.137 +static void unpack_greyf(struct pixel *unp, void *pptr, int count) 10.138 +{ 10.139 + int i; 10.140 + float *pix = pptr; 10.141 + 10.142 + for(i=0; i<count; i++) { 10.143 + unp->r = unp->g = unp->b = *pix++; 10.144 + unp->a = 1.0; 10.145 + unp++; 10.146 + } 10.147 +} 10.148 + 10.149 +static void unpack_rgbf(struct pixel *unp, void *pptr, int count) 10.150 +{ 10.151 + int i; 10.152 + float *pix = pptr; 10.153 + 10.154 + for(i=0; i<count; i++) { 10.155 + unp->r = *pix++; 10.156 + unp->g = *pix++; 10.157 + unp->b = *pix++; 10.158 + unp->a = 1.0; 10.159 + unp++; 10.160 + } 10.161 +} 10.162 + 10.163 +static void unpack_rgbaf(struct pixel *unp, void *pptr, int count) 10.164 +{ 10.165 + int i; 10.166 + float *pix = pptr; 10.167 + 10.168 + for(i=0; i<count; i++) { 10.169 + unp->r = *pix++; 10.170 + unp->g = *pix++; 10.171 + unp->b = *pix++; 10.172 + unp->a = *pix++; 10.173 + unp++; 10.174 + } 10.175 +} 10.176 + 10.177 + 10.178 +static void pack_grey8(void *pptr, struct pixel *unp, int count) 10.179 +{ 10.180 + int i; 10.181 + unsigned char *pix = pptr; 10.182 + 10.183 + for(i=0; i<count; i++) { 10.184 + int lum = (int)(255.0 * (unp->r + unp->g + unp->b) / 3.0); 10.185 + *pix++ = CLAMP(lum, 0, 255); 10.186 + unp++; 10.187 + } 10.188 +} 10.189 + 10.190 +static void pack_rgb24(void *pptr, struct pixel *unp, int count) 10.191 +{ 10.192 + int i; 10.193 + unsigned char *pix = pptr; 10.194 + 10.195 + for(i=0; i<count; i++) { 10.196 + int r = (int)(unp->r * 255.0); 10.197 + int g = (int)(unp->g * 255.0); 10.198 + int b = (int)(unp->b * 255.0); 10.199 + 10.200 + *pix++ = CLAMP(r, 0, 255); 10.201 + *pix++ = CLAMP(g, 0, 255); 10.202 + *pix++ = CLAMP(b, 0, 255); 10.203 + unp++; 10.204 + } 10.205 +} 10.206 + 10.207 +static void pack_rgba32(void *pptr, struct pixel *unp, int count) 10.208 +{ 10.209 + int i; 10.210 + unsigned char *pix = pptr; 10.211 + 10.212 + for(i=0; i<count; i++) { 10.213 + int r = (int)(unp->r * 255.0); 10.214 + int g = (int)(unp->g * 255.0); 10.215 + int b = (int)(unp->b * 255.0); 10.216 + int a = (int)(unp->a * 255.0); 10.217 + 10.218 + *pix++ = CLAMP(r, 0, 255); 10.219 + *pix++ = CLAMP(g, 0, 255); 10.220 + *pix++ = CLAMP(b, 0, 255); 10.221 + *pix++ = CLAMP(a, 0, 255); 10.222 + unp++; 10.223 + } 10.224 +} 10.225 + 10.226 +static void pack_greyf(void *pptr, struct pixel *unp, int count) 10.227 +{ 10.228 + int i; 10.229 + float *pix = pptr; 10.230 + 10.231 + for(i=0; i<count; i++) { 10.232 + *pix++ = (unp->r + unp->g + unp->b) / 3.0; 10.233 + unp++; 10.234 + } 10.235 +} 10.236 + 10.237 +static void pack_rgbf(void *pptr, struct pixel *unp, int count) 10.238 +{ 10.239 + int i; 10.240 + float *pix = pptr; 10.241 + 10.242 + for(i=0; i<count; i++) { 10.243 + *pix++ = unp->r; 10.244 + *pix++ = unp->g; 10.245 + *pix++ = unp->b; 10.246 + unp++; 10.247 + } 10.248 +} 10.249 + 10.250 +static void pack_rgbaf(void *pptr, struct pixel *unp, int count) 10.251 +{ 10.252 + memcpy(pptr, unp, count * sizeof *unp); 10.253 +} 10.254 +
11.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 11.2 +++ b/prototype/imago2/file_jpeg.c Sun Oct 07 02:04:00 2012 +0300 11.3 @@ -0,0 +1,293 @@ 11.4 +/* 11.5 +libimago - a multi-format image file input/output library. 11.6 +Copyright (C) 2010 John Tsiombikas <nuclear@member.fsf.org> 11.7 + 11.8 +This program is free software: you can redistribute it and/or modify 11.9 +it under the terms of the GNU Lesser General Public License as published 11.10 +by the Free Software Foundation, either version 3 of the License, or 11.11 +(at your option) any later version. 11.12 + 11.13 +This program is distributed in the hope that it will be useful, 11.14 +but WITHOUT ANY WARRANTY; without even the implied warranty of 11.15 +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11.16 +GNU Lesser General Public License for more details. 11.17 + 11.18 +You should have received a copy of the GNU Lesser General Public License 11.19 +along with this program. If not, see <http://www.gnu.org/licenses/>. 11.20 +*/ 11.21 + 11.22 +/* -- JPEG module -- */ 11.23 + 11.24 +#include <stdio.h> 11.25 +#include <stdlib.h> 11.26 +#include <string.h> 11.27 + 11.28 +#ifdef WIN32 11.29 +#include <windows.h> 11.30 +#define HAVE_BOOLEAN 11.31 +#endif 11.32 + 11.33 +#include <jpeglib.h> 11.34 +#include "imago2.h" 11.35 +#include "ftype_module.h" 11.36 + 11.37 +#define INPUT_BUF_SIZE 512 11.38 +#define OUTPUT_BUF_SIZE 512 11.39 + 11.40 +/* data source manager: adapted from jdatasrc.c */ 11.41 +struct src_mgr { 11.42 + struct jpeg_source_mgr pub; 11.43 + 11.44 + struct img_io *io; 11.45 + unsigned char buffer[INPUT_BUF_SIZE]; 11.46 + int start_of_file; 11.47 +}; 11.48 + 11.49 +/* data destination manager: adapted from jdatadst.c */ 11.50 +struct dst_mgr { 11.51 + struct jpeg_destination_mgr pub; 11.52 + 11.53 + struct img_io *io; 11.54 + unsigned char buffer[OUTPUT_BUF_SIZE]; 11.55 +}; 11.56 + 11.57 +static int check(struct img_io *io); 11.58 +static int read(struct img_pixmap *img, struct img_io *io); 11.59 +static int write(struct img_pixmap *img, struct img_io *io); 11.60 + 11.61 +/* read source functions */ 11.62 +static void init_source(j_decompress_ptr jd); 11.63 +static int fill_input_buffer(j_decompress_ptr jd); 11.64 +static void skip_input_data(j_decompress_ptr jd, long num_bytes); 11.65 +static void term_source(j_decompress_ptr jd); 11.66 + 11.67 +/* write destination functions */ 11.68 +static void init_destination(j_compress_ptr jc); 11.69 +static int empty_output_buffer(j_compress_ptr jc); 11.70 +static void term_destination(j_compress_ptr jc); 11.71 + 11.72 +int img_register_jpeg(void) 11.73 +{ 11.74 + static struct ftype_module mod = {".jpg", check, read, write}; 11.75 + return img_register_module(&mod); 11.76 +} 11.77 + 11.78 + 11.79 +static int check(struct img_io *io) 11.80 +{ 11.81 + unsigned char sig[10]; 11.82 + 11.83 + long pos = io->seek(0, SEEK_CUR, io->uptr); 11.84 + 11.85 + if(io->read(sig, 10, io->uptr) < 10) { 11.86 + io->seek(pos, SEEK_SET, io->uptr); 11.87 + return -1; 11.88 + } 11.89 + 11.90 + if(memcmp(sig, "\xff\xd8\xff\xe0", 4) != 0 || memcmp(sig + 6, "JFIF", 4) != 0) { 11.91 + io->seek(pos, SEEK_SET, io->uptr); 11.92 + return -1; 11.93 + } 11.94 + io->seek(pos, SEEK_SET, io->uptr); 11.95 + return 0; 11.96 +} 11.97 + 11.98 +static int read(struct img_pixmap *img, struct img_io *io) 11.99 +{ 11.100 + int i, nlines = 0; 11.101 + struct jpeg_decompress_struct cinfo; 11.102 + struct jpeg_error_mgr jerr; 11.103 + struct src_mgr src; 11.104 + unsigned char **scanlines; 11.105 + 11.106 + io->seek(0, SEEK_CUR, io->uptr); 11.107 + 11.108 + cinfo.err = jpeg_std_error(&jerr); /* XXX change... */ 11.109 + jpeg_create_decompress(&cinfo); 11.110 + 11.111 + src.pub.init_source = init_source; 11.112 + src.pub.fill_input_buffer = fill_input_buffer; 11.113 + src.pub.skip_input_data = skip_input_data; 11.114 + src.pub.resync_to_restart = jpeg_resync_to_restart; 11.115 + src.pub.term_source = term_source; 11.116 + src.pub.next_input_byte = 0; 11.117 + src.pub.bytes_in_buffer = 0; 11.118 + src.io = io; 11.119 + cinfo.src = (struct jpeg_source_mgr*)&src; 11.120 + 11.121 + jpeg_read_header(&cinfo, 1); 11.122 + cinfo.out_color_space = JCS_RGB; 11.123 + 11.124 + if(img_set_pixels(img, cinfo.image_width, cinfo.image_height, IMG_FMT_RGB24, 0) == -1) { 11.125 + jpeg_destroy_decompress(&cinfo); 11.126 + return -1; 11.127 + } 11.128 + 11.129 + if(!(scanlines = malloc(img->height * sizeof *scanlines))) { 11.130 + jpeg_destroy_decompress(&cinfo); 11.131 + return -1; 11.132 + } 11.133 + scanlines[0] = img->pixels; 11.134 + for(i=1; i<img->height; i++) { 11.135 + scanlines[i] = scanlines[i - 1] + img->width * img->pixelsz; 11.136 + } 11.137 + 11.138 + jpeg_start_decompress(&cinfo); 11.139 + while(nlines < img->height) { 11.140 + int res = jpeg_read_scanlines(&cinfo, scanlines + nlines, img->height - nlines); 11.141 + nlines += res; 11.142 + } 11.143 + jpeg_finish_decompress(&cinfo); 11.144 + jpeg_destroy_decompress(&cinfo); 11.145 + 11.146 + free(scanlines); 11.147 + return 0; 11.148 +} 11.149 + 11.150 +static int write(struct img_pixmap *img, struct img_io *io) 11.151 +{ 11.152 + int i, nlines = 0; 11.153 + struct jpeg_compress_struct cinfo; 11.154 + struct jpeg_error_mgr jerr; 11.155 + struct dst_mgr dest; 11.156 + struct img_pixmap tmpimg; 11.157 + unsigned char **scanlines; 11.158 + 11.159 + img_init(&tmpimg); 11.160 + 11.161 + if(img->fmt != IMG_FMT_RGB24) { 11.162 + if(img_copy(&tmpimg, img) == -1) { 11.163 + return -1; 11.164 + } 11.165 + if(img_convert(&tmpimg, IMG_FMT_RGB24) == -1) { 11.166 + img_destroy(&tmpimg); 11.167 + return -1; 11.168 + } 11.169 + img = &tmpimg; 11.170 + } 11.171 + 11.172 + if(!(scanlines = malloc(img->height * sizeof *scanlines))) { 11.173 + img_destroy(&tmpimg); 11.174 + return -1; 11.175 + } 11.176 + scanlines[0] = img->pixels; 11.177 + for(i=1; i<img->height; i++) { 11.178 + scanlines[i] = scanlines[i - 1] + img->width * img->pixelsz; 11.179 + } 11.180 + 11.181 + cinfo.err = jpeg_std_error(&jerr); /* XXX */ 11.182 + jpeg_create_compress(&cinfo); 11.183 + 11.184 + dest.pub.init_destination = init_destination; 11.185 + dest.pub.empty_output_buffer = empty_output_buffer; 11.186 + dest.pub.term_destination = term_destination; 11.187 + dest.io = io; 11.188 + cinfo.dest = (struct jpeg_destination_mgr*)&dest; 11.189 + 11.190 + cinfo.image_width = img->width; 11.191 + cinfo.image_height = img->height; 11.192 + cinfo.input_components = 3; 11.193 + cinfo.in_color_space = JCS_RGB; 11.194 + 11.195 + jpeg_set_defaults(&cinfo); 11.196 + 11.197 + jpeg_start_compress(&cinfo, 1); 11.198 + while(nlines < img->height) { 11.199 + int res = jpeg_write_scanlines(&cinfo, scanlines + nlines, img->height - nlines); 11.200 + nlines += res; 11.201 + } 11.202 + jpeg_finish_compress(&cinfo); 11.203 + jpeg_destroy_compress(&cinfo); 11.204 + 11.205 + free(scanlines); 11.206 + img_destroy(&tmpimg); 11.207 + return 0; 11.208 +} 11.209 + 11.210 +/* -- read source functions -- 11.211 + * the following functions are adapted from jdatasrc.c in jpeglib 11.212 + */ 11.213 +static void init_source(j_decompress_ptr jd) 11.214 +{ 11.215 + struct src_mgr *src = (struct src_mgr*)jd->src; 11.216 + src->start_of_file = 1; 11.217 +} 11.218 + 11.219 +static int fill_input_buffer(j_decompress_ptr jd) 11.220 +{ 11.221 + struct src_mgr *src = (struct src_mgr*)jd->src; 11.222 + size_t nbytes; 11.223 + 11.224 + nbytes = src->io->read(src->buffer, INPUT_BUF_SIZE, src->io->uptr); 11.225 + 11.226 + if(nbytes <= 0) { 11.227 + if(src->start_of_file) { 11.228 + return 0; 11.229 + } 11.230 + /* insert a fake EOI marker */ 11.231 + src->buffer[0] = 0xff; 11.232 + src->buffer[1] = JPEG_EOI; 11.233 + nbytes = 2; 11.234 + } 11.235 + 11.236 + src->pub.next_input_byte = src->buffer; 11.237 + src->pub.bytes_in_buffer = nbytes; 11.238 + src->start_of_file = 0; 11.239 + return 1; 11.240 +} 11.241 + 11.242 +static void skip_input_data(j_decompress_ptr jd, long num_bytes) 11.243 +{ 11.244 + struct src_mgr *src = (struct src_mgr*)jd->src; 11.245 + 11.246 + if(num_bytes > 0) { 11.247 + while(num_bytes > (long)src->pub.bytes_in_buffer) { 11.248 + num_bytes -= (long)src->pub.bytes_in_buffer; 11.249 + fill_input_buffer(jd); 11.250 + } 11.251 + src->pub.next_input_byte += (size_t)num_bytes; 11.252 + src->pub.bytes_in_buffer -= (size_t)num_bytes; 11.253 + } 11.254 +} 11.255 + 11.256 +static void term_source(j_decompress_ptr jd) 11.257 +{ 11.258 + /* nothing to see here, move along */ 11.259 +} 11.260 + 11.261 + 11.262 +/* -- write destination functions -- 11.263 + * the following functions are adapted from jdatadst.c in jpeglib 11.264 + */ 11.265 +static void init_destination(j_compress_ptr jc) 11.266 +{ 11.267 + struct dst_mgr *dest = (struct dst_mgr*)jc->dest; 11.268 + 11.269 + dest->pub.next_output_byte = dest->buffer; 11.270 + dest->pub.free_in_buffer = OUTPUT_BUF_SIZE; 11.271 +} 11.272 + 11.273 +static int empty_output_buffer(j_compress_ptr jc) 11.274 +{ 11.275 + struct dst_mgr *dest = (struct dst_mgr*)jc->dest; 11.276 + 11.277 + if(dest->io->write(dest->buffer, OUTPUT_BUF_SIZE, dest->io->uptr) != OUTPUT_BUF_SIZE) { 11.278 + return 0; 11.279 + } 11.280 + 11.281 + dest->pub.next_output_byte = dest->buffer; 11.282 + dest->pub.free_in_buffer = OUTPUT_BUF_SIZE; 11.283 + return 1; 11.284 +} 11.285 + 11.286 +static void term_destination(j_compress_ptr jc) 11.287 +{ 11.288 + struct dst_mgr *dest = (struct dst_mgr*)jc->dest; 11.289 + size_t datacount = OUTPUT_BUF_SIZE - dest->pub.free_in_buffer; 11.290 + 11.291 + /* write any remaining data in the buffer */ 11.292 + if(datacount > 0) { 11.293 + dest->io->write(dest->buffer, datacount, dest->io->uptr); 11.294 + } 11.295 + /* XXX flush? ... */ 11.296 +}
12.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 12.2 +++ b/prototype/imago2/file_png.c Sun Oct 07 02:04:00 2012 +0300 12.3 @@ -0,0 +1,244 @@ 12.4 +/* 12.5 +libimago - a multi-format image file input/output library. 12.6 +Copyright (C) 2010 John Tsiombikas <nuclear@member.fsf.org> 12.7 + 12.8 +This program is free software: you can redistribute it and/or modify 12.9 +it under the terms of the GNU Lesser General Public License as published 12.10 +by the Free Software Foundation, either version 3 of the License, or 12.11 +(at your option) any later version. 12.12 + 12.13 +This program is distributed in the hope that it will be useful, 12.14 +but WITHOUT ANY WARRANTY; without even the implied warranty of 12.15 +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12.16 +GNU Lesser General Public License for more details. 12.17 + 12.18 +You should have received a copy of the GNU Lesser General Public License 12.19 +along with this program. If not, see <http://www.gnu.org/licenses/>. 12.20 +*/ 12.21 + 12.22 +/* -- PNG module -- */ 12.23 + 12.24 +#include <stdlib.h> 12.25 +#include <png.h> 12.26 +#include "imago2.h" 12.27 +#include "ftype_module.h" 12.28 + 12.29 +static int check_file(struct img_io *io); 12.30 +static int read_file(struct img_pixmap *img, struct img_io *io); 12.31 +static int write_file(struct img_pixmap *img, struct img_io *io); 12.32 + 12.33 +static void read_func(png_struct *png, unsigned char *data, size_t len); 12.34 +static void write_func(png_struct *png, unsigned char *data, size_t len); 12.35 +static void flush_func(png_struct *png); 12.36 + 12.37 +static int png_type_to_fmt(int color_type, int channel_bits); 12.38 +static int fmt_to_png_type(enum img_fmt fmt); 12.39 + 12.40 + 12.41 +int img_register_png(void) 12.42 +{ 12.43 + static struct ftype_module mod = {".png", check_file, read_file, write_file}; 12.44 + return img_register_module(&mod); 12.45 +} 12.46 + 12.47 +static int check_file(struct img_io *io) 12.48 +{ 12.49 + unsigned char sig[8]; 12.50 + int res; 12.51 + long pos = io->seek(0, SEEK_CUR, io->uptr); 12.52 + 12.53 + if(io->read(sig, 8, io->uptr) < 8) { 12.54 + io->seek(pos, SEEK_SET, io->uptr); 12.55 + return -1; 12.56 + } 12.57 + 12.58 + res = png_sig_cmp(sig, 0, 8) == 0 ? 0 : -1; 12.59 + io->seek(pos, SEEK_SET, io->uptr); 12.60 + return res; 12.61 +} 12.62 + 12.63 +static int read_file(struct img_pixmap *img, struct img_io *io) 12.64 +{ 12.65 + png_struct *png; 12.66 + png_info *info; 12.67 + unsigned char **lineptr, *dest; 12.68 + int i, channel_bits, color_type, ilace_type, compression, filtering, fmt; 12.69 + png_uint_32 xsz, ysz; 12.70 + 12.71 + if(!(png = png_create_read_struct(PNG_LIBPNG_VER_STRING, 0, 0, 0))) { 12.72 + return -1; 12.73 + } 12.74 + 12.75 + if(!(info = png_create_info_struct(png))) { 12.76 + png_destroy_read_struct(&png, 0, 0); 12.77 + return -1; 12.78 + } 12.79 + 12.80 + if(setjmp(png_jmpbuf(png))) { 12.81 + png_destroy_read_struct(&png, &info, 0); 12.82 + return -1; 12.83 + } 12.84 + 12.85 + png_set_read_fn(png, io, read_func); 12.86 + png_set_sig_bytes(png, 0); 12.87 + png_read_png(png, info, 0, 0); 12.88 + 12.89 + png_get_IHDR(png, info, &xsz, &ysz, &channel_bits, &color_type, &ilace_type, 12.90 + &compression, &filtering); 12.91 + if((fmt = png_type_to_fmt(color_type, channel_bits)) == -1) { 12.92 + png_destroy_read_struct(&png, &info, 0); 12.93 + return -1; 12.94 + } 12.95 + 12.96 + if(img_set_pixels(img, xsz, ysz, fmt, 0) == -1) { 12.97 + png_destroy_read_struct(&png, &info, 0); 12.98 + return -1; 12.99 + } 12.100 + 12.101 + lineptr = (unsigned char**)png_get_rows(png, info); 12.102 + 12.103 + dest = img->pixels; 12.104 + for(i=0; i<ysz; i++) { 12.105 + memcpy(dest, lineptr[i], xsz * img->pixelsz); 12.106 + dest += xsz * img->pixelsz; 12.107 + } 12.108 + png_destroy_read_struct(&png, &info, 0); 12.109 + return 0; 12.110 +} 12.111 + 12.112 + 12.113 +static int write_file(struct img_pixmap *img, struct img_io *io) 12.114 +{ 12.115 + png_struct *png; 12.116 + png_info *info; 12.117 + png_text txt; 12.118 + struct img_pixmap tmpimg; 12.119 + unsigned char **rows; 12.120 + unsigned char *pixptr; 12.121 + int i, coltype; 12.122 + 12.123 + img_init(&tmpimg); 12.124 + 12.125 + if(!(png = png_create_write_struct(PNG_LIBPNG_VER_STRING, 0, 0, 0))) { 12.126 + return -1; 12.127 + } 12.128 + if(!(info = png_create_info_struct(png))) { 12.129 + png_destroy_write_struct(&png, 0); 12.130 + return -1; 12.131 + } 12.132 + 12.133 + /* if the input image is floating-point, we need to convert it to integer */ 12.134 + if(img_is_float(img)) { 12.135 + if(img_copy(&tmpimg, img) == -1) { 12.136 + return -1; 12.137 + } 12.138 + if(img_to_integer(&tmpimg) == -1) { 12.139 + img_destroy(&tmpimg); 12.140 + return -1; 12.141 + } 12.142 + img = &tmpimg; 12.143 + } 12.144 + 12.145 + txt.compression = PNG_TEXT_COMPRESSION_NONE; 12.146 + txt.key = "Software"; 12.147 + txt.text = "libimago2"; 12.148 + txt.text_length = 0; 12.149 + 12.150 + if(setjmp(png_jmpbuf(png))) { 12.151 + png_destroy_write_struct(&png, &info); 12.152 + img_destroy(&tmpimg); 12.153 + return -1; 12.154 + } 12.155 + png_set_write_fn(png, io, write_func, flush_func); 12.156 + 12.157 + coltype = fmt_to_png_type(img->fmt); 12.158 + png_set_IHDR(png, info, img->width, img->height, 8, coltype, PNG_INTERLACE_NONE, 12.159 + PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT); 12.160 + png_set_text(png, info, &txt, 1); 12.161 + 12.162 + if(!(rows = malloc(img->height * sizeof *rows))) { 12.163 + png_destroy_write_struct(&png, &info); 12.164 + img_destroy(&tmpimg); 12.165 + return -1; 12.166 + } 12.167 + 12.168 + pixptr = img->pixels; 12.169 + for(i=0; i<img->height; i++) { 12.170 + rows[i] = pixptr; 12.171 + pixptr += img->width * img->pixelsz; 12.172 + } 12.173 + png_set_rows(png, info, rows); 12.174 + 12.175 + png_write_png(png, info, 0, 0); 12.176 + png_write_end(png, info); 12.177 + png_destroy_write_struct(&png, &info); 12.178 + 12.179 + free(rows); 12.180 + 12.181 + img_destroy(&tmpimg); 12.182 + return 0; 12.183 +} 12.184 + 12.185 +static void read_func(png_struct *png, unsigned char *data, size_t len) 12.186 +{ 12.187 + struct img_io *io = (struct img_io*)png_get_io_ptr(png); 12.188 + 12.189 + if(io->read(data, len, io->uptr) == -1) { 12.190 + longjmp(png_jmpbuf(png), 1); 12.191 + } 12.192 +} 12.193 + 12.194 +static void write_func(png_struct *png, unsigned char *data, size_t len) 12.195 +{ 12.196 + struct img_io *io = (struct img_io*)png_get_io_ptr(png); 12.197 + 12.198 + if(io->write(data, len, io->uptr) == -1) { 12.199 + longjmp(png_jmpbuf(png), 1); 12.200 + } 12.201 +} 12.202 + 12.203 +static void flush_func(png_struct *png) 12.204 +{ 12.205 + /* XXX does it matter that we can't flush? */ 12.206 +} 12.207 + 12.208 +static int png_type_to_fmt(int color_type, int channel_bits) 12.209 +{ 12.210 + /* we don't support non-8bit-per-channel images yet */ 12.211 + if(channel_bits > 8) { 12.212 + return -1; 12.213 + } 12.214 + 12.215 + switch(color_type) { 12.216 + case PNG_COLOR_TYPE_RGB: 12.217 + return IMG_FMT_RGB24; 12.218 + 12.219 + case PNG_COLOR_TYPE_RGB_ALPHA: 12.220 + return IMG_FMT_RGBA32; 12.221 + 12.222 + case PNG_COLOR_TYPE_GRAY: 12.223 + return IMG_FMT_GREY8; 12.224 + 12.225 + default: 12.226 + break; 12.227 + } 12.228 + return -1; 12.229 +} 12.230 + 12.231 +static int fmt_to_png_type(enum img_fmt fmt) 12.232 +{ 12.233 + switch(fmt) { 12.234 + case IMG_FMT_GREY8: 12.235 + return PNG_COLOR_TYPE_GRAY; 12.236 + 12.237 + case IMG_FMT_RGB24: 12.238 + return PNG_COLOR_TYPE_RGB; 12.239 + 12.240 + case IMG_FMT_RGBA32: 12.241 + return PNG_COLOR_TYPE_RGBA; 12.242 + 12.243 + default: 12.244 + break; 12.245 + } 12.246 + return -1; 12.247 +}
13.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 13.2 +++ b/prototype/imago2/file_ppm.c Sun Oct 07 02:04:00 2012 +0300 13.3 @@ -0,0 +1,153 @@ 13.4 +/* 13.5 +libimago - a multi-format image file input/output library. 13.6 +Copyright (C) 2010 John Tsiombikas <nuclear@member.fsf.org> 13.7 + 13.8 +This program is free software: you can redistribute it and/or modify 13.9 +it under the terms of the GNU Lesser General Public License as published 13.10 +by the Free Software Foundation, either version 3 of the License, or 13.11 +(at your option) any later version. 13.12 + 13.13 +This program is distributed in the hope that it will be useful, 13.14 +but WITHOUT ANY WARRANTY; without even the implied warranty of 13.15 +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13.16 +GNU Lesser General Public License for more details. 13.17 + 13.18 +You should have received a copy of the GNU Lesser General Public License 13.19 +along with this program. If not, see <http://www.gnu.org/licenses/>. 13.20 +*/ 13.21 + 13.22 +/* -- Portable Pixmap (PPM) module -- */ 13.23 + 13.24 +#include <string.h> 13.25 +#include "imago2.h" 13.26 +#include "ftype_module.h" 13.27 + 13.28 +static int check(struct img_io *io); 13.29 +static int read(struct img_pixmap *img, struct img_io *io); 13.30 +static int write(struct img_pixmap *img, struct img_io *io); 13.31 + 13.32 +int img_register_ppm(void) 13.33 +{ 13.34 + static struct ftype_module mod = {".ppm", check, read, write}; 13.35 + return img_register_module(&mod); 13.36 +} 13.37 + 13.38 + 13.39 +static int check(struct img_io *io) 13.40 +{ 13.41 + char id[2]; 13.42 + int res = -1; 13.43 + long pos = io->seek(0, SEEK_CUR, io->uptr); 13.44 + 13.45 + if(io->read(id, 2, io->uptr) < 2) { 13.46 + io->seek(pos, SEEK_SET, io->uptr); 13.47 + return -1; 13.48 + } 13.49 + 13.50 + if(id[0] == 'P' && (id[1] == '6' || id[1] == '3')) { 13.51 + res = 0; 13.52 + } 13.53 + io->seek(pos, SEEK_SET, io->uptr); 13.54 + return res; 13.55 +} 13.56 + 13.57 +static int iofgetc(struct img_io *io) 13.58 +{ 13.59 + char c; 13.60 + return io->read(&c, 1, io->uptr) < 1 ? -1 : c; 13.61 +} 13.62 + 13.63 +static char *iofgets(char *buf, int size, struct img_io *io) 13.64 +{ 13.65 + int c; 13.66 + char *ptr = buf; 13.67 + 13.68 + while(--size > 0 && (c = iofgetc(io)) != -1) { 13.69 + *ptr++ = c; 13.70 + if(c == '\n') break; 13.71 + } 13.72 + *ptr = 0; 13.73 + 13.74 + return ptr == buf ? 0 : buf; 13.75 +} 13.76 + 13.77 +/* TODO: implement P3 reading */ 13.78 +static int read(struct img_pixmap *img, struct img_io *io) 13.79 +{ 13.80 + char buf[256]; 13.81 + int xsz, ysz, maxval, got_hdrlines = 1; 13.82 + 13.83 + if(!iofgets(buf, sizeof buf, io)) { 13.84 + return -1; 13.85 + } 13.86 + if(!(buf[0] == 'P' && (buf[1] == '6' || buf[1] == '3'))) { 13.87 + return -1; 13.88 + } 13.89 + 13.90 + while(got_hdrlines < 3 && iofgets(buf, sizeof buf, io)) { 13.91 + if(buf[0] == '#') continue; 13.92 + 13.93 + switch(got_hdrlines) { 13.94 + case 1: 13.95 + if(sscanf(buf, "%d %d\n", &xsz, &ysz) < 2) { 13.96 + return -1; 13.97 + } 13.98 + break; 13.99 + 13.100 + case 2: 13.101 + if(sscanf(buf, "%d\n", &maxval) < 1) { 13.102 + return -1; 13.103 + } 13.104 + default: 13.105 + break; 13.106 + } 13.107 + got_hdrlines++; 13.108 + } 13.109 + 13.110 + if(xsz < 1 || ysz < 1 || maxval != 255) { 13.111 + return -1; 13.112 + } 13.113 + 13.114 + if(img_set_pixels(img, xsz, ysz, IMG_FMT_RGB24, 0) == -1) { 13.115 + return -1; 13.116 + } 13.117 + 13.118 + if(io->read(img->pixels, xsz * ysz * 3, io->uptr) < xsz * ysz * 3) { 13.119 + return -1; 13.120 + } 13.121 + return 0; 13.122 +} 13.123 + 13.124 +static int write(struct img_pixmap *img, struct img_io *io) 13.125 +{ 13.126 + int sz; 13.127 + char buf[256]; 13.128 + struct img_pixmap tmpimg; 13.129 + 13.130 + img_init(&tmpimg); 13.131 + 13.132 + if(img->fmt != IMG_FMT_RGB24) { 13.133 + if(img_copy(&tmpimg, img) == -1) { 13.134 + return -1; 13.135 + } 13.136 + if(img_convert(&tmpimg, IMG_FMT_RGB24) == -1) { 13.137 + return -1; 13.138 + } 13.139 + img = &tmpimg; 13.140 + } 13.141 + 13.142 + sprintf(buf, "P6\n#written by libimago2\n%d %d\n255\n", img->width, img->height); 13.143 + if(io->write(buf, strlen(buf), io->uptr) < strlen(buf)) { 13.144 + img_destroy(&tmpimg); 13.145 + return -1; 13.146 + } 13.147 + 13.148 + sz = img->width * img->height * 3; 13.149 + if(io->write(img->pixels, sz, io->uptr) < sz) { 13.150 + img_destroy(&tmpimg); 13.151 + return -1; 13.152 + } 13.153 + 13.154 + img_destroy(&tmpimg); 13.155 + return 0; 13.156 +}
14.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 14.2 +++ b/prototype/imago2/file_rgbe.c Sun Oct 07 02:04:00 2012 +0300 14.3 @@ -0,0 +1,501 @@ 14.4 +/* This file contains code to read and write four byte rgbe file format 14.5 + * developed by Greg Ward. It handles the conversions between rgbe and 14.6 + * pixels consisting of floats. The data is assumed to be an array of floats. 14.7 + * By default there are three floats per pixel in the order red, green, blue. 14.8 + * (RGBE_DATA_??? values control this.) 14.9 + * 14.10 + * written by Bruce Walter (bjw@graphics.cornell.edu) 5/26/95 14.11 + * based on code written by Greg Ward 14.12 + * minor modifications by John Tsiombikas (nuclear@member.fsf.org) apr.9 2007 14.13 + */ 14.14 + 14.15 +#include <stdio.h> 14.16 +#include <stdlib.h> 14.17 +#include <string.h> 14.18 +#include <math.h> 14.19 +#include <ctype.h> 14.20 +#include <errno.h> 14.21 +#include "imago2.h" 14.22 +#include "ftype_module.h" 14.23 + 14.24 + 14.25 +typedef struct { 14.26 + int valid; /* indicate which fields are valid */ 14.27 + char programtype[16]; /* listed at beginning of file to identify it 14.28 + * after "#?". defaults to "RGBE" */ 14.29 + float gamma; /* image has already been gamma corrected with 14.30 + * given gamma. defaults to 1.0 (no correction) */ 14.31 + float exposure; /* a value of 1.0 in an image corresponds to 14.32 + * <exposure> watts/steradian/m^2. 14.33 + * defaults to 1.0 */ 14.34 +} rgbe_header_info; 14.35 + 14.36 + 14.37 +static int check(struct img_io *io); 14.38 +static int read(struct img_pixmap *img, struct img_io *io); 14.39 +static int write(struct img_pixmap *img, struct img_io *io); 14.40 + 14.41 +static int rgbe_read_header(struct img_io *io, int *width, int *height, rgbe_header_info * info); 14.42 +static int rgbe_read_pixels_rle(struct img_io *io, float *data, int scanline_width, int num_scanlines); 14.43 + 14.44 + 14.45 +int img_register_rgbe(void) 14.46 +{ 14.47 + static struct ftype_module mod = {".rgbe", check, read, write}; 14.48 + return img_register_module(&mod); 14.49 +} 14.50 + 14.51 + 14.52 +static int check(struct img_io *io) 14.53 +{ 14.54 + int xsz, ysz, res; 14.55 + long pos = io->seek(0, SEEK_CUR, io->uptr); 14.56 + 14.57 + rgbe_header_info hdr; 14.58 + res = rgbe_read_header(io, &xsz, &ysz, &hdr); 14.59 + 14.60 + io->seek(pos, SEEK_SET, io->uptr); 14.61 + return res; 14.62 +} 14.63 + 14.64 +static int read(struct img_pixmap *img, struct img_io *io) 14.65 +{ 14.66 + int xsz, ysz; 14.67 + rgbe_header_info hdr; 14.68 + 14.69 + if(rgbe_read_header(io, &xsz, &ysz, &hdr) == -1) { 14.70 + return -1; 14.71 + } 14.72 + 14.73 + if(img_set_pixels(img, xsz, ysz, IMG_FMT_RGBF, 0) == -1) { 14.74 + return -1; 14.75 + } 14.76 + if(rgbe_read_pixels_rle(io, img->pixels, xsz, ysz) == -1) { 14.77 + return -1; 14.78 + } 14.79 + return 0; 14.80 +} 14.81 + 14.82 +static int write(struct img_pixmap *img, struct img_io *io) 14.83 +{ 14.84 + return -1; /* TODO */ 14.85 +} 14.86 + 14.87 + 14.88 +static int iofgetc(struct img_io *io) 14.89 +{ 14.90 + char c; 14.91 + return io->read(&c, 1, io->uptr) < 1 ? -1 : c; 14.92 +} 14.93 + 14.94 +static char *iofgets(char *buf, int size, struct img_io *io) 14.95 +{ 14.96 + int c; 14.97 + char *ptr = buf; 14.98 + 14.99 + while(--size > 0 && (c = iofgetc(io)) != -1) { 14.100 + *ptr++ = c; 14.101 + if(c == '\n') break; 14.102 + } 14.103 + *ptr = 0; 14.104 + 14.105 + return ptr == buf ? 0 : buf; 14.106 +} 14.107 + 14.108 + 14.109 +/* flags indicating which fields in an rgbe_header_info are valid */ 14.110 +#define RGBE_VALID_PROGRAMTYPE 0x01 14.111 +#define RGBE_VALID_GAMMA 0x02 14.112 +#define RGBE_VALID_EXPOSURE 0x04 14.113 + 14.114 +/* return codes for rgbe routines */ 14.115 +#define RGBE_RETURN_SUCCESS 0 14.116 +#define RGBE_RETURN_FAILURE -1 14.117 + 14.118 + 14.119 +#if defined(__cplusplus) || defined(GNUC) || __STDC_VERSION >= 199901L 14.120 +#define INLINE inline 14.121 +#else 14.122 +#define INLINE 14.123 +#endif 14.124 + 14.125 +/* offsets to red, green, and blue components in a data (float) pixel */ 14.126 +#define RGBE_DATA_RED 0 14.127 +#define RGBE_DATA_GREEN 1 14.128 +#define RGBE_DATA_BLUE 2 14.129 + 14.130 +/* number of floats per pixel */ 14.131 +#define RGBE_DATA_SIZE 3 14.132 + 14.133 +enum rgbe_error_codes { 14.134 + rgbe_read_error, 14.135 + rgbe_write_error, 14.136 + rgbe_format_error, 14.137 + rgbe_memory_error 14.138 +}; 14.139 + 14.140 + 14.141 +/* default error routine. change this to change error handling */ 14.142 +static int rgbe_error(int rgbe_error_code, char *msg) 14.143 +{ 14.144 + switch (rgbe_error_code) { 14.145 + case rgbe_read_error: 14.146 + fprintf(stderr, "RGBE read error: %s\n", strerror(errno)); 14.147 + break; 14.148 + 14.149 + case rgbe_write_error: 14.150 + fprintf(stderr, "RGBE write error: %s\n", strerror(errno)); 14.151 + break; 14.152 + 14.153 + case rgbe_format_error: 14.154 + fprintf(stderr, "RGBE bad file format: %s\n", msg); 14.155 + break; 14.156 + 14.157 + default: 14.158 + case rgbe_memory_error: 14.159 + fprintf(stderr, "RGBE error: %s\n", msg); 14.160 + } 14.161 + return RGBE_RETURN_FAILURE; 14.162 +} 14.163 + 14.164 +/* standard conversion from float pixels to rgbe pixels */ 14.165 +/*static INLINE void float2rgbe(unsigned char rgbe[4], float red, float green, float blue) 14.166 +{ 14.167 + float v; 14.168 + int e; 14.169 + 14.170 + v = red; 14.171 + if(green > v) 14.172 + v = green; 14.173 + if(blue > v) 14.174 + v = blue; 14.175 + if(v < 1e-32) { 14.176 + rgbe[0] = rgbe[1] = rgbe[2] = rgbe[3] = 0; 14.177 + } else { 14.178 + v = frexp(v, &e) * 256.0 / v; 14.179 + rgbe[0] = (unsigned char)(red * v); 14.180 + rgbe[1] = (unsigned char)(green * v); 14.181 + rgbe[2] = (unsigned char)(blue * v); 14.182 + rgbe[3] = (unsigned char)(e + 128); 14.183 + } 14.184 +}*/ 14.185 + 14.186 +/* standard conversion from rgbe to float pixels */ 14.187 +/* note: Ward uses ldexp(col+0.5,exp-(128+8)). However we wanted pixels */ 14.188 +/* in the range [0,1] to map back into the range [0,1]. */ 14.189 +static INLINE void rgbe2float(float *red, float *green, float *blue, unsigned char rgbe[4]) 14.190 +{ 14.191 + float f; 14.192 + 14.193 + if(rgbe[3]) { /*nonzero pixel */ 14.194 + f = ldexp(1.0, rgbe[3] - (int)(128 + 8)); 14.195 + *red = rgbe[0] * f; 14.196 + *green = rgbe[1] * f; 14.197 + *blue = rgbe[2] * f; 14.198 + } else 14.199 + *red = *green = *blue = 0.0; 14.200 +} 14.201 + 14.202 +#if 0 14.203 +/* default minimal header. modify if you want more information in header */ 14.204 +static int rgbe_write_header(FILE * fp, int width, int height, rgbe_header_info * info) 14.205 +{ 14.206 + char *programtype = "RGBE"; 14.207 + 14.208 + if(info && (info->valid & RGBE_VALID_PROGRAMTYPE)) 14.209 + programtype = info->programtype; 14.210 + if(fprintf(fp, "#?%s\n", programtype) < 0) 14.211 + return rgbe_error(rgbe_write_error, NULL); 14.212 + /* The #? is to identify file type, the programtype is optional. */ 14.213 + if(info && (info->valid & RGBE_VALID_GAMMA)) { 14.214 + if(fprintf(fp, "GAMMA=%g\n", info->gamma) < 0) 14.215 + return rgbe_error(rgbe_write_error, NULL); 14.216 + } 14.217 + if(info && (info->valid & RGBE_VALID_EXPOSURE)) { 14.218 + if(fprintf(fp, "EXPOSURE=%g\n", info->exposure) < 0) 14.219 + return rgbe_error(rgbe_write_error, NULL); 14.220 + } 14.221 + if(fprintf(fp, "FORMAT=32-bit_rle_rgbe\n\n") < 0) 14.222 + return rgbe_error(rgbe_write_error, NULL); 14.223 + if(fprintf(fp, "-Y %d +X %d\n", height, width) < 0) 14.224 + return rgbe_error(rgbe_write_error, NULL); 14.225 + return RGBE_RETURN_SUCCESS; 14.226 +} 14.227 +#endif 14.228 + 14.229 +/* minimal header reading. modify if you want to parse more information */ 14.230 +static int rgbe_read_header(struct img_io *io, int *width, int *height, rgbe_header_info * info) 14.231 +{ 14.232 + char buf[128]; 14.233 + float tempf; 14.234 + int i; 14.235 + 14.236 + if(info) { 14.237 + info->valid = 0; 14.238 + info->programtype[0] = 0; 14.239 + info->gamma = info->exposure = 1.0; 14.240 + } 14.241 + if(iofgets(buf, sizeof(buf) / sizeof(buf[0]), io) == NULL) 14.242 + return RGBE_RETURN_FAILURE;/*rgbe_error(rgbe_read_error, NULL);*/ 14.243 + if((buf[0] != '#') || (buf[1] != '?')) { 14.244 + /* if you want to require the magic token then uncomment the next line */ 14.245 + /*return rgbe_error(rgbe_format_error,"bad initial token"); */ 14.246 + } else if(info) { 14.247 + info->valid |= RGBE_VALID_PROGRAMTYPE; 14.248 + for(i = 0; i < sizeof(info->programtype) - 1; i++) { 14.249 + if((buf[i + 2] == 0) || isspace(buf[i + 2])) 14.250 + break; 14.251 + info->programtype[i] = buf[i + 2]; 14.252 + } 14.253 + info->programtype[i] = 0; 14.254 + if(iofgets(buf, sizeof(buf) / sizeof(buf[0]), io) == 0) 14.255 + return rgbe_error(rgbe_read_error, NULL); 14.256 + } 14.257 + for(;;) { 14.258 + if((buf[0] == 0) || (buf[0] == '\n')) 14.259 + return RGBE_RETURN_FAILURE;/*rgbe_error(rgbe_format_error, "no FORMAT specifier found");*/ 14.260 + else if(strcmp(buf, "FORMAT=32-bit_rle_rgbe\n") == 0) 14.261 + break; /* format found so break out of loop */ 14.262 + else if(info && (sscanf(buf, "GAMMA=%g", &tempf) == 1)) { 14.263 + info->gamma = tempf; 14.264 + info->valid |= RGBE_VALID_GAMMA; 14.265 + } else if(info && (sscanf(buf, "EXPOSURE=%g", &tempf) == 1)) { 14.266 + info->exposure = tempf; 14.267 + info->valid |= RGBE_VALID_EXPOSURE; 14.268 + } 14.269 + if(iofgets(buf, sizeof(buf) / sizeof(buf[0]), io) == 0) 14.270 + return RGBE_RETURN_FAILURE;/*rgbe_error(rgbe_read_error, NULL);*/ 14.271 + } 14.272 + if(iofgets(buf, sizeof(buf) / sizeof(buf[0]), io) == 0) 14.273 + return RGBE_RETURN_FAILURE;/*rgbe_error(rgbe_read_error, NULL);*/ 14.274 + if(strcmp(buf, "\n") != 0) 14.275 + return RGBE_RETURN_FAILURE;/*rgbe_error(rgbe_format_error, "missing blank line after FORMAT specifier");*/ 14.276 + if(iofgets(buf, sizeof(buf) / sizeof(buf[0]), io) == 0) 14.277 + return RGBE_RETURN_FAILURE;/*rgbe_error(rgbe_read_error, NULL);*/ 14.278 + if(sscanf(buf, "-Y %d +X %d", height, width) < 2) 14.279 + return RGBE_RETURN_FAILURE;/*rgbe_error(rgbe_format_error, "missing image size specifier");*/ 14.280 + return RGBE_RETURN_SUCCESS; 14.281 +} 14.282 + 14.283 +#if 0 14.284 +/* simple write routine that does not use run length encoding */ 14.285 + 14.286 +/* These routines can be made faster by allocating a larger buffer and 14.287 + fread-ing and fwrite-ing the data in larger chunks */ 14.288 +static int rgbe_write_pixels(FILE * fp, float *data, int numpixels) 14.289 +{ 14.290 + unsigned char rgbe[4]; 14.291 + 14.292 + while(numpixels-- > 0) { 14.293 + float2rgbe(rgbe, data[RGBE_DATA_RED], data[RGBE_DATA_GREEN], data[RGBE_DATA_BLUE]); 14.294 + data += RGBE_DATA_SIZE; 14.295 + if(fwrite(rgbe, sizeof(rgbe), 1, fp) < 1) 14.296 + return rgbe_error(rgbe_write_error, NULL); 14.297 + } 14.298 + return RGBE_RETURN_SUCCESS; 14.299 +} 14.300 +#endif 14.301 + 14.302 +/* simple read routine. will not correctly handle run length encoding */ 14.303 +static int rgbe_read_pixels(struct img_io *io, float *data, int numpixels) 14.304 +{ 14.305 + unsigned char rgbe[4]; 14.306 + 14.307 + while(numpixels-- > 0) { 14.308 + if(io->read(rgbe, sizeof(rgbe), io->uptr) < 1) 14.309 + return rgbe_error(rgbe_read_error, NULL); 14.310 + rgbe2float(&data[RGBE_DATA_RED], &data[RGBE_DATA_GREEN], &data[RGBE_DATA_BLUE], rgbe); 14.311 + data += RGBE_DATA_SIZE; 14.312 + } 14.313 + return RGBE_RETURN_SUCCESS; 14.314 +} 14.315 + 14.316 +#if 0 14.317 +/* The code below is only needed for the run-length encoded files. */ 14.318 + 14.319 +/* Run length encoding adds considerable complexity but does */ 14.320 + 14.321 +/* save some space. For each scanline, each channel (r,g,b,e) is */ 14.322 + 14.323 +/* encoded separately for better compression. */ 14.324 + 14.325 +static int rgbe_write_bytes_rle(struct img_io *io, unsigned char *data, int numbytes) 14.326 +{ 14.327 +#define MINRUNLENGTH 4 14.328 + int cur, beg_run, run_count, old_run_count, nonrun_count; 14.329 + unsigned char buf[2]; 14.330 + 14.331 + cur = 0; 14.332 + while(cur < numbytes) { 14.333 + beg_run = cur; 14.334 + /* find next run of length at least 4 if one exists */ 14.335 + run_count = old_run_count = 0; 14.336 + while((run_count < MINRUNLENGTH) && (beg_run < numbytes)) { 14.337 + beg_run += run_count; 14.338 + old_run_count = run_count; 14.339 + run_count = 1; 14.340 + while((beg_run + run_count < numbytes) && (run_count < 127) 14.341 + && (data[beg_run] == data[beg_run + run_count])) 14.342 + run_count++; 14.343 + } 14.344 + /* if data before next big run is a short run then write it as such */ 14.345 + if((old_run_count > 1) && (old_run_count == beg_run - cur)) { 14.346 + buf[0] = 128 + old_run_count; /*write short run */ 14.347 + buf[1] = data[cur]; 14.348 + if(fwrite(buf, sizeof(buf[0]) * 2, 1, fp) < 1) 14.349 + return rgbe_error(rgbe_write_error, NULL); 14.350 + cur = beg_run; 14.351 + } 14.352 + /* write out bytes until we reach the start of the next run */ 14.353 + while(cur < beg_run) { 14.354 + nonrun_count = beg_run - cur; 14.355 + if(nonrun_count > 128) 14.356 + nonrun_count = 128; 14.357 + buf[0] = nonrun_count; 14.358 + if(fwrite(buf, sizeof(buf[0]), 1, fp) < 1) 14.359 + return rgbe_error(rgbe_write_error, NULL); 14.360 + if(fwrite(&data[cur], sizeof(data[0]) * nonrun_count, 1, fp) < 1) 14.361 + return rgbe_error(rgbe_write_error, NULL); 14.362 + cur += nonrun_count; 14.363 + } 14.364 + /* write out next run if one was found */ 14.365 + if(run_count >= MINRUNLENGTH) { 14.366 + buf[0] = 128 + run_count; 14.367 + buf[1] = data[beg_run]; 14.368 + if(fwrite(buf, sizeof(buf[0]) * 2, 1, fp) < 1) 14.369 + return rgbe_error(rgbe_write_error, NULL); 14.370 + cur += run_count; 14.371 + } 14.372 + } 14.373 + return RGBE_RETURN_SUCCESS; 14.374 +#undef MINRUNLENGTH 14.375 +} 14.376 + 14.377 +static int rgbe_write_pixels_rle(struct img_io *io, float *data, int scanline_width, int num_scanlines) 14.378 +{ 14.379 + unsigned char rgbe[4]; 14.380 + unsigned char *buffer; 14.381 + int i, err; 14.382 + 14.383 + if((scanline_width < 8) || (scanline_width > 0x7fff)) 14.384 + /* run length encoding is not allowed so write flat */ 14.385 + return rgbe_write_pixels(io, data, scanline_width * num_scanlines); 14.386 + buffer = (unsigned char *)malloc(sizeof(unsigned char) * 4 * scanline_width); 14.387 + if(buffer == NULL) 14.388 + /* no buffer space so write flat */ 14.389 + return rgbe_write_pixels(fp, data, scanline_width * num_scanlines); 14.390 + while(num_scanlines-- > 0) { 14.391 + rgbe[0] = 2; 14.392 + rgbe[1] = 2; 14.393 + rgbe[2] = scanline_width >> 8; 14.394 + rgbe[3] = scanline_width & 0xFF; 14.395 + if(fwrite(rgbe, sizeof(rgbe), 1, fp) < 1) { 14.396 + free(buffer); 14.397 + return rgbe_error(rgbe_write_error, NULL); 14.398 + } 14.399 + for(i = 0; i < scanline_width; i++) { 14.400 + float2rgbe(rgbe, data[RGBE_DATA_RED], data[RGBE_DATA_GREEN], data[RGBE_DATA_BLUE]); 14.401 + buffer[i] = rgbe[0]; 14.402 + buffer[i + scanline_width] = rgbe[1]; 14.403 + buffer[i + 2 * scanline_width] = rgbe[2]; 14.404 + buffer[i + 3 * scanline_width] = rgbe[3]; 14.405 + data += RGBE_DATA_SIZE; 14.406 + } 14.407 + /* write out each of the four channels separately run length encoded */ 14.408 + /* first red, then green, then blue, then exponent */ 14.409 + for(i = 0; i < 4; i++) { 14.410 + if((err = rgbe_write_bytes_rle(fp, &buffer[i * scanline_width], 14.411 + scanline_width)) != RGBE_RETURN_SUCCESS) { 14.412 + free(buffer); 14.413 + return err; 14.414 + } 14.415 + } 14.416 + } 14.417 + free(buffer); 14.418 + return RGBE_RETURN_SUCCESS; 14.419 +} 14.420 +#endif 14.421 + 14.422 +static int rgbe_read_pixels_rle(struct img_io *io, float *data, int scanline_width, int num_scanlines) 14.423 +{ 14.424 + unsigned char rgbe[4], *scanline_buffer, *ptr, *ptr_end; 14.425 + int i, count; 14.426 + unsigned char buf[2]; 14.427 + 14.428 + if((scanline_width < 8) || (scanline_width > 0x7fff)) 14.429 + /* run length encoding is not allowed so read flat */ 14.430 + return rgbe_read_pixels(io, data, scanline_width * num_scanlines); 14.431 + scanline_buffer = NULL; 14.432 + /* read in each successive scanline */ 14.433 + while(num_scanlines > 0) { 14.434 + if(io->read(rgbe, sizeof(rgbe), io->uptr) < 1) { 14.435 + free(scanline_buffer); 14.436 + return rgbe_error(rgbe_read_error, NULL); 14.437 + } 14.438 + if((rgbe[0] != 2) || (rgbe[1] != 2) || (rgbe[2] & 0x80)) { 14.439 + /* this file is not run length encoded */ 14.440 + rgbe2float(&data[0], &data[1], &data[2], rgbe); 14.441 + data += RGBE_DATA_SIZE; 14.442 + free(scanline_buffer); 14.443 + return rgbe_read_pixels(io, data, scanline_width * num_scanlines - 1); 14.444 + } 14.445 + if((((int)rgbe[2]) << 8 | rgbe[3]) != scanline_width) { 14.446 + free(scanline_buffer); 14.447 + return rgbe_error(rgbe_format_error, "wrong scanline width"); 14.448 + } 14.449 + if(scanline_buffer == NULL) 14.450 + scanline_buffer = (unsigned char *) 14.451 + malloc(sizeof(unsigned char) * 4 * scanline_width); 14.452 + if(scanline_buffer == NULL) 14.453 + return rgbe_error(rgbe_memory_error, "unable to allocate buffer space"); 14.454 + 14.455 + ptr = &scanline_buffer[0]; 14.456 + /* read each of the four channels for the scanline into the buffer */ 14.457 + for(i = 0; i < 4; i++) { 14.458 + ptr_end = &scanline_buffer[(i + 1) * scanline_width]; 14.459 + while(ptr < ptr_end) { 14.460 + if(io->read(buf, sizeof(buf[0]) * 2, io->uptr) < 1) { 14.461 + free(scanline_buffer); 14.462 + return rgbe_error(rgbe_read_error, NULL); 14.463 + } 14.464 + if(buf[0] > 128) { 14.465 + /* a run of the same value */ 14.466 + count = buf[0] - 128; 14.467 + if((count == 0) || (count > ptr_end - ptr)) { 14.468 + free(scanline_buffer); 14.469 + return rgbe_error(rgbe_format_error, "bad scanline data"); 14.470 + } 14.471 + while(count-- > 0) 14.472 + *ptr++ = buf[1]; 14.473 + } else { 14.474 + /* a non-run */ 14.475 + count = buf[0]; 14.476 + if((count == 0) || (count > ptr_end - ptr)) { 14.477 + free(scanline_buffer); 14.478 + return rgbe_error(rgbe_format_error, "bad scanline data"); 14.479 + } 14.480 + *ptr++ = buf[1]; 14.481 + if(--count > 0) { 14.482 + if(io->read(ptr, sizeof(*ptr) * count, io->uptr) < 1) { 14.483 + free(scanline_buffer); 14.484 + return rgbe_error(rgbe_read_error, NULL); 14.485 + } 14.486 + ptr += count; 14.487 + } 14.488 + } 14.489 + } 14.490 + } 14.491 + /* now convert data from buffer into floats */ 14.492 + for(i = 0; i < scanline_width; i++) { 14.493 + rgbe[0] = scanline_buffer[i]; 14.494 + rgbe[1] = scanline_buffer[i + scanline_width]; 14.495 + rgbe[2] = scanline_buffer[i + 2 * scanline_width]; 14.496 + rgbe[3] = scanline_buffer[i + 3 * scanline_width]; 14.497 + rgbe2float(&data[RGBE_DATA_RED], &data[RGBE_DATA_GREEN], &data[RGBE_DATA_BLUE], rgbe); 14.498 + data += RGBE_DATA_SIZE; 14.499 + } 14.500 + num_scanlines--; 14.501 + } 14.502 + free(scanline_buffer); 14.503 + return RGBE_RETURN_SUCCESS; 14.504 +}
15.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 15.2 +++ b/prototype/imago2/ftype_module.c Sun Oct 07 02:04:00 2012 +0300 15.3 @@ -0,0 +1,118 @@ 15.4 +/* 15.5 +libimago - a multi-format image file input/output library. 15.6 +Copyright (C) 2010 John Tsiombikas <nuclear@member.fsf.org> 15.7 + 15.8 +This program is free software: you can redistribute it and/or modify 15.9 +it under the terms of the GNU Lesser General Public License as published 15.10 +by the Free Software Foundation, either version 3 of the License, or 15.11 +(at your option) any later version. 15.12 + 15.13 +This program is distributed in the hope that it will be useful, 15.14 +but WITHOUT ANY WARRANTY; without even the implied warranty of 15.15 +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15.16 +GNU Lesser General Public License for more details. 15.17 + 15.18 +You should have received a copy of the GNU Lesser General Public License 15.19 +along with this program. If not, see <http://www.gnu.org/licenses/>. 15.20 +*/ 15.21 + 15.22 +#include <stdlib.h> 15.23 +#include <string.h> 15.24 +#include "ftype_module.h" 15.25 + 15.26 +static struct list_node { 15.27 + struct ftype_module *module; 15.28 + struct list_node *next; 15.29 +} *modules; 15.30 + 15.31 +/* defined in modules.c which is generated by configure */ 15.32 +void img_modules_init(); 15.33 + 15.34 +static int done_init; 15.35 + 15.36 +int img_register_module(struct ftype_module *mod) 15.37 +{ 15.38 + struct list_node *node; 15.39 + 15.40 + if(!(node = malloc(sizeof *node))) { 15.41 + return -1; 15.42 + } 15.43 + 15.44 + node->module = mod; 15.45 + node->next = modules; 15.46 + modules = node; 15.47 + return 0; 15.48 +} 15.49 + 15.50 +struct ftype_module *img_find_format_module(struct img_io *io) 15.51 +{ 15.52 + struct list_node *node; 15.53 + 15.54 + if(!done_init) { 15.55 + img_modules_init(); 15.56 + done_init = 1; 15.57 + } 15.58 + 15.59 + node = modules; 15.60 + while(node) { 15.61 + if(node->module->check(io) != -1) { 15.62 + return node->module; 15.63 + } 15.64 + node = node->next; 15.65 + } 15.66 + return 0; 15.67 +} 15.68 + 15.69 +struct ftype_module *img_guess_format(const char *fname) 15.70 +{ 15.71 + struct list_node *node; 15.72 + char *suffix; 15.73 + int suffix_len; 15.74 + 15.75 + if(!done_init) { 15.76 + img_modules_init(); 15.77 + done_init = 1; 15.78 + } 15.79 + 15.80 + if(!(suffix = strrchr(fname, '.'))) { 15.81 + return 0; /* no suffix, can't guess ... */ 15.82 + } 15.83 + suffix_len = strlen(suffix); 15.84 + 15.85 + node = modules; 15.86 + while(node) { 15.87 + char *suflist = node->module->suffix; 15.88 + char *start, *end; 15.89 + 15.90 + while(*suflist) { 15.91 + if(!(start = strstr(suflist, suffix))) { 15.92 + break; 15.93 + } 15.94 + end = start + suffix_len; 15.95 + 15.96 + if(*end == ':' || *end == 0) { 15.97 + return node->module; /* found it */ 15.98 + } 15.99 + suflist = end; 15.100 + } 15.101 + 15.102 + node = node->next; 15.103 + } 15.104 + return 0; 15.105 +} 15.106 + 15.107 +struct ftype_module *img_get_module(int idx) 15.108 +{ 15.109 + struct list_node *node; 15.110 + 15.111 + if(!done_init) { 15.112 + img_modules_init(); 15.113 + done_init = 1; 15.114 + } 15.115 + 15.116 + node = modules; 15.117 + while(node && idx--) { 15.118 + node = node->next; 15.119 + } 15.120 + return node->module; 15.121 +}
16.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 16.2 +++ b/prototype/imago2/ftype_module.h Sun Oct 07 02:04:00 2012 +0300 16.3 @@ -0,0 +1,39 @@ 16.4 +/* 16.5 +libimago - a multi-format image file input/output library. 16.6 +Copyright (C) 2010 John Tsiombikas <nuclear@member.fsf.org> 16.7 + 16.8 +This program is free software: you can redistribute it and/or modify 16.9 +it under the terms of the GNU Lesser General Public License as published 16.10 +by the Free Software Foundation, either version 3 of the License, or 16.11 +(at your option) any later version. 16.12 + 16.13 +This program is distributed in the hope that it will be useful, 16.14 +but WITHOUT ANY WARRANTY; without even the implied warranty of 16.15 +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16.16 +GNU Lesser General Public License for more details. 16.17 + 16.18 +You should have received a copy of the GNU Lesser General Public License 16.19 +along with this program. If not, see <http://www.gnu.org/licenses/>. 16.20 +*/ 16.21 + 16.22 +#ifndef FTYPE_MODULE_H_ 16.23 +#define FTYPE_MODULE_H_ 16.24 + 16.25 +#include "imago2.h" 16.26 + 16.27 +struct ftype_module { 16.28 + char *suffix; /* used for format autodetection during saving only */ 16.29 + 16.30 + int (*check)(struct img_io *io); 16.31 + int (*read)(struct img_pixmap *img, struct img_io *io); 16.32 + int (*write)(struct img_pixmap *img, struct img_io *io); 16.33 +}; 16.34 + 16.35 +int img_register_module(struct ftype_module *mod); 16.36 + 16.37 +struct ftype_module *img_find_format_module(struct img_io *io); 16.38 +struct ftype_module *img_guess_format(const char *fname); 16.39 +struct ftype_module *img_get_module(int idx); 16.40 + 16.41 + 16.42 +#endif /* FTYPE_MODULE_H_ */
17.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 17.2 +++ b/prototype/imago2/imago2.c Sun Oct 07 02:04:00 2012 +0300 17.3 @@ -0,0 +1,449 @@ 17.4 +/* 17.5 +libimago - a multi-format image file input/output library. 17.6 +Copyright (C) 2010 John Tsiombikas <nuclear@member.fsf.org> 17.7 + 17.8 +This program is free software: you can redistribute it and/or modify 17.9 +it under the terms of the GNU Lesser General Public License as published 17.10 +by the Free Software Foundation, either version 3 of the License, or 17.11 +(at your option) any later version. 17.12 + 17.13 +This program is distributed in the hope that it will be useful, 17.14 +but WITHOUT ANY WARRANTY; without even the implied warranty of 17.15 +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17.16 +GNU Lesser General Public License for more details. 17.17 + 17.18 +You should have received a copy of the GNU Lesser General Public License 17.19 +along with this program. If not, see <http://www.gnu.org/licenses/>. 17.20 +*/ 17.21 + 17.22 +#include <stdio.h> 17.23 +#include <stdlib.h> 17.24 +#include <string.h> 17.25 +#include "imago2.h" 17.26 +#include "ftype_module.h" 17.27 + 17.28 +static int pixel_size(enum img_fmt fmt); 17.29 +static size_t def_read(void *buf, size_t bytes, void *uptr); 17.30 +static size_t def_write(void *buf, size_t bytes, void *uptr); 17.31 +static long def_seek(long offset, int whence, void *uptr); 17.32 + 17.33 + 17.34 +void img_init(struct img_pixmap *img) 17.35 +{ 17.36 + img->pixels = 0; 17.37 + img->width = img->height = 0; 17.38 + img->fmt = IMG_FMT_RGBA32; 17.39 + img->pixelsz = pixel_size(img->fmt); 17.40 + img->name = 0; 17.41 +} 17.42 + 17.43 + 17.44 +void img_destroy(struct img_pixmap *img) 17.45 +{ 17.46 + free(img->pixels); 17.47 + img->pixels = 0; /* just in case... */ 17.48 + img->width = img->height = 0xbadbeef; 17.49 + free(img->name); 17.50 +} 17.51 + 17.52 +struct img_pixmap *img_create(void) 17.53 +{ 17.54 + struct img_pixmap *p; 17.55 + 17.56 + if(!(p = malloc(sizeof *p))) { 17.57 + return 0; 17.58 + } 17.59 + img_init(p); 17.60 + return p; 17.61 +} 17.62 + 17.63 +void img_free(struct img_pixmap *img) 17.64 +{ 17.65 + img_destroy(img); 17.66 + free(img); 17.67 +} 17.68 + 17.69 +int img_set_name(struct img_pixmap *img, const char *name) 17.70 +{ 17.71 + char *tmp; 17.72 + 17.73 + if(!(tmp = malloc(strlen(name) + 1))) { 17.74 + return -1; 17.75 + } 17.76 + strcpy(tmp, name); 17.77 + img->name = tmp; 17.78 + return 0; 17.79 +} 17.80 + 17.81 +int img_set_format(struct img_pixmap *img, enum img_fmt fmt) 17.82 +{ 17.83 + if(img->pixels) { 17.84 + return img_convert(img, fmt); 17.85 + } 17.86 + img->fmt = fmt; 17.87 + return 0; 17.88 +} 17.89 + 17.90 +int img_copy(struct img_pixmap *dest, struct img_pixmap *src) 17.91 +{ 17.92 + return img_set_pixels(dest, src->width, src->height, src->fmt, src->pixels); 17.93 +} 17.94 + 17.95 +int img_set_pixels(struct img_pixmap *img, int w, int h, enum img_fmt fmt, void *pix) 17.96 +{ 17.97 + void *newpix; 17.98 + int pixsz = pixel_size(fmt); 17.99 + 17.100 + if(!(newpix = malloc(w * h * pixsz))) { 17.101 + return -1; 17.102 + } 17.103 + 17.104 + if(pix) { 17.105 + memcpy(newpix, pix, w * h * pixsz); 17.106 + } else { 17.107 + memset(newpix, 0, w * h * pixsz); 17.108 + } 17.109 + 17.110 + free(img->pixels); 17.111 + img->pixels = newpix; 17.112 + img->width = w; 17.113 + img->height = h; 17.114 + img->pixelsz = pixsz; 17.115 + img->fmt = fmt; 17.116 + return 0; 17.117 +} 17.118 + 17.119 +void *img_load_pixels(const char *fname, int *xsz, int *ysz, enum img_fmt fmt) 17.120 +{ 17.121 + struct img_pixmap img; 17.122 + 17.123 + img_init(&img); 17.124 + 17.125 + if(img_load(&img, fname) == -1) { 17.126 + return 0; 17.127 + } 17.128 + if(img.fmt != fmt) { 17.129 + if(img_convert(&img, fmt) == -1) { 17.130 + img_destroy(&img); 17.131 + return 0; 17.132 + } 17.133 + } 17.134 + 17.135 + *xsz = img.width; 17.136 + *ysz = img.height; 17.137 + return img.pixels; 17.138 +} 17.139 + 17.140 +int img_save_pixels(const char *fname, void *pix, int xsz, int ysz, enum img_fmt fmt) 17.141 +{ 17.142 + struct img_pixmap img; 17.143 + 17.144 + img_init(&img); 17.145 + img.fmt = fmt; 17.146 + img.name = (char*)fname; 17.147 + img.width = xsz; 17.148 + img.height = ysz; 17.149 + img.pixels = pix; 17.150 + 17.151 + return img_save(&img, fname); 17.152 +} 17.153 + 17.154 +void img_free_pixels(void *pix) 17.155 +{ 17.156 + free(pix); 17.157 +} 17.158 + 17.159 +int img_load(struct img_pixmap *img, const char *fname) 17.160 +{ 17.161 + int res; 17.162 + FILE *fp; 17.163 + 17.164 + if(!(fp = fopen(fname, "rb"))) { 17.165 + return -1; 17.166 + } 17.167 + res = img_read_file(img, fp); 17.168 + fclose(fp); 17.169 + return res; 17.170 +} 17.171 + 17.172 +/* TODO implement filetype selection */ 17.173 +int img_save(struct img_pixmap *img, const char *fname) 17.174 +{ 17.175 + int res; 17.176 + FILE *fp; 17.177 + 17.178 + img_set_name(img, fname); 17.179 + 17.180 + if(!(fp = fopen(fname, "wb"))) { 17.181 + return -1; 17.182 + } 17.183 + res = img_write_file(img, fp); 17.184 + fclose(fp); 17.185 + return res; 17.186 +} 17.187 + 17.188 +int img_read_file(struct img_pixmap *img, FILE *fp) 17.189 +{ 17.190 + struct img_io io = {0, def_read, def_write, def_seek}; 17.191 + 17.192 + io.uptr = fp; 17.193 + return img_read(img, &io); 17.194 +} 17.195 + 17.196 +int img_write_file(struct img_pixmap *img, FILE *fp) 17.197 +{ 17.198 + struct img_io io = {0, def_read, def_write, def_seek}; 17.199 + 17.200 + io.uptr = fp; 17.201 + return img_write(img, &io); 17.202 +} 17.203 + 17.204 +int img_read(struct img_pixmap *img, struct img_io *io) 17.205 +{ 17.206 + struct ftype_module *mod; 17.207 + 17.208 + if((mod = img_find_format_module(io))) { 17.209 + return mod->read(img, io); 17.210 + } 17.211 + return -1; 17.212 +} 17.213 + 17.214 +int img_write(struct img_pixmap *img, struct img_io *io) 17.215 +{ 17.216 + struct ftype_module *mod; 17.217 + 17.218 + if(!img->name || !(mod = img_guess_format(img->name))) { 17.219 + /* TODO throw some sort of warning? */ 17.220 + /* TODO implement some sort of module priority or let the user specify? */ 17.221 + if(!(mod = img_get_module(0))) { 17.222 + return -1; 17.223 + } 17.224 + } 17.225 + 17.226 + return mod->write(img, io); 17.227 +} 17.228 + 17.229 +int img_to_float(struct img_pixmap *img) 17.230 +{ 17.231 + enum img_fmt targ_fmt; 17.232 + 17.233 + switch(img->fmt) { 17.234 + case IMG_FMT_GREY8: 17.235 + targ_fmt = IMG_FMT_GREYF; 17.236 + break; 17.237 + 17.238 + case IMG_FMT_RGB24: 17.239 + targ_fmt = IMG_FMT_RGBF; 17.240 + break; 17.241 + 17.242 + case IMG_FMT_RGBA32: 17.243 + targ_fmt = IMG_FMT_RGBAF; 17.244 + break; 17.245 + 17.246 + default: 17.247 + return 0; /* already float */ 17.248 + } 17.249 + 17.250 + return img_convert(img, targ_fmt); 17.251 +} 17.252 + 17.253 +int img_to_integer(struct img_pixmap *img) 17.254 +{ 17.255 + enum img_fmt targ_fmt; 17.256 + 17.257 + switch(img->fmt) { 17.258 + case IMG_FMT_GREYF: 17.259 + targ_fmt = IMG_FMT_GREY8; 17.260 + break; 17.261 + 17.262 + case IMG_FMT_RGBF: 17.263 + targ_fmt = IMG_FMT_RGB24; 17.264 + break; 17.265 + 17.266 + case IMG_FMT_RGBAF: 17.267 + targ_fmt = IMG_FMT_RGBA32; 17.268 + break; 17.269 + 17.270 + default: 17.271 + return 0; /* already integer */ 17.272 + } 17.273 + 17.274 + return img_convert(img, targ_fmt); 17.275 +} 17.276 + 17.277 +int img_is_float(struct img_pixmap *img) 17.278 +{ 17.279 + return img->fmt >= IMG_FMT_GREYF && img->fmt <= IMG_FMT_RGBAF; 17.280 +} 17.281 + 17.282 +int img_has_alpha(struct img_pixmap *img) 17.283 +{ 17.284 + if(img->fmt == IMG_FMT_RGBA32 || img->fmt == IMG_FMT_RGBAF) { 17.285 + return 1; 17.286 + } 17.287 + return 0; 17.288 +} 17.289 + 17.290 + 17.291 +void img_setpixel(struct img_pixmap *img, int x, int y, void *pixel) 17.292 +{ 17.293 + char *dest = (char*)img->pixels + (y * img->width + x) * img->pixelsz; 17.294 + memcpy(dest, pixel, img->pixelsz); 17.295 +} 17.296 + 17.297 +void img_getpixel(struct img_pixmap *img, int x, int y, void *pixel) 17.298 +{ 17.299 + char *dest = (char*)img->pixels + (y * img->width + x) * img->pixelsz; 17.300 + memcpy(pixel, dest, img->pixelsz); 17.301 +} 17.302 + 17.303 +void img_setpixel1i(struct img_pixmap *img, int x, int y, int pix) 17.304 +{ 17.305 + img_setpixel4i(img, x, y, pix, pix, pix, pix); 17.306 +} 17.307 + 17.308 +void img_setpixel1f(struct img_pixmap *img, int x, int y, float pix) 17.309 +{ 17.310 + img_setpixel4f(img, x, y, pix, pix, pix, pix); 17.311 +} 17.312 + 17.313 +void img_setpixel4i(struct img_pixmap *img, int x, int y, int r, int g, int b, int a) 17.314 +{ 17.315 + if(img_is_float(img)) { 17.316 + img_setpixel4f(img, x, y, r / 255.0, g / 255.0, b / 255.0, a / 255.0); 17.317 + } else { 17.318 + unsigned char pixel[4]; 17.319 + pixel[0] = r; 17.320 + pixel[1] = g; 17.321 + pixel[2] = b; 17.322 + pixel[3] = a; 17.323 + 17.324 + img_setpixel(img, x, y, pixel); 17.325 + } 17.326 +} 17.327 + 17.328 +void img_setpixel4f(struct img_pixmap *img, int x, int y, float r, float g, float b, float a) 17.329 +{ 17.330 + if(img_is_float(img)) { 17.331 + float pixel[4]; 17.332 + pixel[0] = r; 17.333 + pixel[1] = g; 17.334 + pixel[2] = b; 17.335 + pixel[3] = a; 17.336 + 17.337 + img_setpixel(img, x, y, pixel); 17.338 + } else { 17.339 + img_setpixel4i(img, x, y, (int)(r * 255.0), (int)(g * 255.0), (int)(b * 255.0), (int)(a * 255.0)); 17.340 + } 17.341 +} 17.342 + 17.343 +void img_getpixel1i(struct img_pixmap *img, int x, int y, int *pix) 17.344 +{ 17.345 + int junk[3]; 17.346 + img_getpixel4i(img, x, y, pix, junk, junk + 1, junk + 2); 17.347 +} 17.348 + 17.349 +void img_getpixel1f(struct img_pixmap *img, int x, int y, float *pix) 17.350 +{ 17.351 + float junk[3]; 17.352 + img_getpixel4f(img, x, y, pix, junk, junk + 1, junk + 2); 17.353 +} 17.354 + 17.355 +void img_getpixel4i(struct img_pixmap *img, int x, int y, int *r, int *g, int *b, int *a) 17.356 +{ 17.357 + if(img_is_float(img)) { 17.358 + float pixel[4] = {0, 0, 0, 0}; 17.359 + img_getpixel(img, x, y, pixel); 17.360 + *r = pixel[0] * 255.0; 17.361 + *g = pixel[1] * 255.0; 17.362 + *b = pixel[2] * 255.0; 17.363 + *a = pixel[3] * 255.0; 17.364 + } else { 17.365 + unsigned char pixel[4]; 17.366 + img_getpixel(img, x, y, pixel); 17.367 + *r = pixel[0]; 17.368 + *g = pixel[1]; 17.369 + *b = pixel[2]; 17.370 + *a = pixel[3]; 17.371 + } 17.372 +} 17.373 + 17.374 +void img_getpixel4f(struct img_pixmap *img, int x, int y, float *r, float *g, float *b, float *a) 17.375 +{ 17.376 + if(img_is_float(img)) { 17.377 + float pixel[4] = {0, 0, 0, 0}; 17.378 + img_getpixel(img, x, y, pixel); 17.379 + *r = pixel[0]; 17.380 + *g = pixel[1]; 17.381 + *b = pixel[2]; 17.382 + *a = pixel[3]; 17.383 + } else { 17.384 + unsigned char pixel[4]; 17.385 + img_getpixel(img, x, y, pixel); 17.386 + *r = pixel[0] / 255.0; 17.387 + *g = pixel[1] / 255.0; 17.388 + *b = pixel[2] / 255.0; 17.389 + *a = pixel[3] / 255.0; 17.390 + } 17.391 +} 17.392 + 17.393 +void img_io_set_user_data(struct img_io *io, void *uptr) 17.394 +{ 17.395 + io->uptr = uptr; 17.396 +} 17.397 + 17.398 +void img_io_set_read_func(struct img_io *io, size_t (*read)(void*, size_t, void*)) 17.399 +{ 17.400 + io->read = read; 17.401 +} 17.402 + 17.403 +void img_io_set_write_func(struct img_io *io, size_t (*write)(void*, size_t, void*)) 17.404 +{ 17.405 + io->write = write; 17.406 +} 17.407 + 17.408 +void img_io_set_seek_func(struct img_io *io, long (*seek)(long, int, void*)) 17.409 +{ 17.410 + io->seek = seek; 17.411 +} 17.412 + 17.413 + 17.414 +static int pixel_size(enum img_fmt fmt) 17.415 +{ 17.416 + switch(fmt) { 17.417 + case IMG_FMT_GREY8: 17.418 + return 1; 17.419 + case IMG_FMT_RGB24: 17.420 + return 3; 17.421 + case IMG_FMT_RGBA32: 17.422 + return 4; 17.423 + case IMG_FMT_GREYF: 17.424 + return sizeof(float); 17.425 + case IMG_FMT_RGBF: 17.426 + return 3 * sizeof(float); 17.427 + case IMG_FMT_RGBAF: 17.428 + return 4 * sizeof(float); 17.429 + default: 17.430 + break; 17.431 + } 17.432 + return 0; 17.433 +} 17.434 + 17.435 +static size_t def_read(void *buf, size_t bytes, void *uptr) 17.436 +{ 17.437 + return uptr ? fread(buf, 1, bytes, uptr) : 0; 17.438 +} 17.439 + 17.440 +static size_t def_write(void *buf, size_t bytes, void *uptr) 17.441 +{ 17.442 + return uptr ? fwrite(buf, 1, bytes, uptr) : 0; 17.443 +} 17.444 + 17.445 +static long def_seek(long offset, int whence, void *uptr) 17.446 +{ 17.447 + if(!uptr || fseek(uptr, offset, whence) == -1) { 17.448 + return -1; 17.449 + } 17.450 + return ftell(uptr); 17.451 +} 17.452 +
18.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 18.2 +++ b/prototype/imago2/imago2.h Sun Oct 07 02:04:00 2012 +0300 18.3 @@ -0,0 +1,222 @@ 18.4 +/* 18.5 +libimago - a multi-format image file input/output library. 18.6 +Copyright (C) 2010-2012 John Tsiombikas <nuclear@member.fsf.org> 18.7 + 18.8 +This program is free software: you can redistribute it and/or modify 18.9 +it under the terms of the GNU Lesser General Public License as published 18.10 +by the Free Software Foundation, either version 3 of the License, or 18.11 +(at your option) any later version. 18.12 + 18.13 +This program is distributed in the hope that it will be useful, 18.14 +but WITHOUT ANY WARRANTY; without even the implied warranty of 18.15 +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18.16 +GNU Lesser General Public License for more details. 18.17 + 18.18 +You should have received a copy of the GNU Lesser General Public License 18.19 +along with this program. If not, see <http://www.gnu.org/licenses/>. 18.20 +*/ 18.21 + 18.22 +#ifndef IMAGO2_H_ 18.23 +#define IMAGO2_H_ 18.24 + 18.25 +#include <stdio.h> 18.26 + 18.27 +#ifdef __cplusplus 18.28 +#define IMG_OPTARG(arg, val) arg = val 18.29 +#else 18.30 +#define IMG_OPTARG(arg, val) arg 18.31 +#endif 18.32 + 18.33 +/* XXX if you change this make sure to also change pack/unpack arrays in conv.c */ 18.34 +enum img_fmt { 18.35 + IMG_FMT_GREY8, 18.36 + IMG_FMT_RGB24, 18.37 + IMG_FMT_RGBA32, 18.38 + IMG_FMT_GREYF, 18.39 + IMG_FMT_RGBF, 18.40 + IMG_FMT_RGBAF, 18.41 + 18.42 + NUM_IMG_FMT 18.43 +}; 18.44 + 18.45 +struct img_pixmap { 18.46 + void *pixels; 18.47 + int width, height; 18.48 + enum img_fmt fmt; 18.49 + int pixelsz; 18.50 + char *name; 18.51 +}; 18.52 + 18.53 +struct img_io { 18.54 + void *uptr; /* user-data */ 18.55 + 18.56 + size_t (*read)(void *buf, size_t bytes, void *uptr); 18.57 + size_t (*write)(void *buf, size_t bytes, void *uptr); 18.58 + long (*seek)(long offs, int whence, void *uptr); 18.59 +}; 18.60 + 18.61 +#ifdef __cplusplus 18.62 +extern "C" { 18.63 +#endif 18.64 + 18.65 +/* initialize the img_pixmap structure */ 18.66 +void img_init(struct img_pixmap *img); 18.67 +/* destroys the img_pixmap structure, freeing the pixel buffer (if available) 18.68 + * and any other memory held by the pixmap. 18.69 + */ 18.70 +void img_destroy(struct img_pixmap *img); 18.71 + 18.72 +/* convenience function that allocates an img_pixmap struct and then initializes it. 18.73 + * returns null if the malloc fails. 18.74 + */ 18.75 +struct img_pixmap *img_create(void); 18.76 +/* frees a pixmap previously allocated with img_create (free followed by img_destroy) */ 18.77 +void img_free(struct img_pixmap *img); 18.78 + 18.79 +int img_set_name(struct img_pixmap *img, const char *name); 18.80 + 18.81 +/* set the image pixel format */ 18.82 +int img_set_format(struct img_pixmap *img, enum img_fmt fmt); 18.83 + 18.84 +/* copies one pixmap to another. 18.85 + * equivalent to: img_set_pixels(dest, src->width, src->height, src->fmt, src->pixels) 18.86 + */ 18.87 +int img_copy(struct img_pixmap *dest, struct img_pixmap *src); 18.88 + 18.89 +/* allocates a pixel buffer of the specified dimensions and format, and copies the 18.90 + * pixels given through the pix pointer into it. 18.91 + * the pix pointer can be null, in which case there's no copy, just allocation. 18.92 + * 18.93 + * C++: fmt and pix have default parameters IMG_FMT_RGBA32 and null respectively. 18.94 + */ 18.95 +int img_set_pixels(struct img_pixmap *img, int w, int h, IMG_OPTARG(enum img_fmt fmt, IMG_FMT_RGBA32), IMG_OPTARG(void *pix, 0)); 18.96 + 18.97 +/* Simplified image loading 18.98 + * Loads the specified file, and returns a pointer to an array of pixels of the 18.99 + * requested pixel format. The width and height of the image are returned through 18.100 + * the xsz and ysz pointers. 18.101 + * If the image cannot be loaded, the function returns null. 18.102 + * 18.103 + * C++: the format argument is optional and defaults to IMG_FMT_RGBA32 18.104 + */ 18.105 +void *img_load_pixels(const char *fname, int *xsz, int *ysz, IMG_OPTARG(enum img_fmt fmt, IMG_FMT_RGBA32)); 18.106 + 18.107 +/* Simplified image saving 18.108 + * Reads an array of pixels supplied through the pix pointer, of dimensions xsz 18.109 + * and ysz, and pixel-format fmt, and saves it to a file. 18.110 + * The output filetype is guessed by the filename suffix. 18.111 + * 18.112 + * C++: the format argument is optional and defaults to IMG_FMT_RGBA32 18.113 + */ 18.114 +int img_save_pixels(const char *fname, void *pix, int xsz, int ysz, IMG_OPTARG(enum img_fmt fmt, IMG_FMT_RGBA32)); 18.115 + 18.116 +/* Frees the memory allocated by img_load_pixels */ 18.117 +void img_free_pixels(void *pix); 18.118 + 18.119 +/* Loads an image file into the supplied pixmap */ 18.120 +int img_load(struct img_pixmap *img, const char *fname); 18.121 +/* Saves the supplied pixmap to a file. The output filetype is guessed by the filename suffix */ 18.122 +int img_save(struct img_pixmap *img, const char *fname); 18.123 + 18.124 +/* Reads an image from an open FILE* into the supplied pixmap */ 18.125 +int img_read_file(struct img_pixmap *img, FILE *fp); 18.126 +/* Writes the supplied pixmap to an open FILE* */ 18.127 +int img_write_file(struct img_pixmap *img, FILE *fp); 18.128 + 18.129 +/* Reads an image using user-defined file-i/o functions (see img_io_set_*) */ 18.130 +int img_read(struct img_pixmap *img, struct img_io *io); 18.131 +/* Writes an image using user-defined file-i/o functions (see img_io_set_*) */ 18.132 +int img_write(struct img_pixmap *img, struct img_io *io); 18.133 + 18.134 +/* Converts an image to the specified pixel format */ 18.135 +int img_convert(struct img_pixmap *img, enum img_fmt tofmt); 18.136 + 18.137 +/* Converts an image from an integer pixel format to the corresponding floating point one */ 18.138 +int img_to_float(struct img_pixmap *img); 18.139 +/* Converts an image from a floating point pixel format to the corresponding integer one */ 18.140 +int img_to_integer(struct img_pixmap *img); 18.141 + 18.142 +/* Returns non-zero (true) if the supplied image is in a floating point pixel format */ 18.143 +int img_is_float(struct img_pixmap *img); 18.144 +/* Returns non-zero (true) if the supplied image has an alpha channel */ 18.145 +int img_has_alpha(struct img_pixmap *img); 18.146 + 18.147 + 18.148 +/* don't use these for anything performance-critical */ 18.149 +void img_setpixel(struct img_pixmap *img, int x, int y, void *pixel); 18.150 +void img_getpixel(struct img_pixmap *img, int x, int y, void *pixel); 18.151 + 18.152 +void img_setpixel1i(struct img_pixmap *img, int x, int y, int pix); 18.153 +void img_setpixel1f(struct img_pixmap *img, int x, int y, float pix); 18.154 +void img_setpixel4i(struct img_pixmap *img, int x, int y, int r, int g, int b, int a); 18.155 +void img_setpixel4f(struct img_pixmap *img, int x, int y, float r, float g, float b, float a); 18.156 + 18.157 +void img_getpixel1i(struct img_pixmap *img, int x, int y, int *pix); 18.158 +void img_getpixel1f(struct img_pixmap *img, int x, int y, float *pix); 18.159 +void img_getpixel4i(struct img_pixmap *img, int x, int y, int *r, int *g, int *b, int *a); 18.160 +void img_getpixel4f(struct img_pixmap *img, int x, int y, float *r, float *g, float *b, float *a); 18.161 + 18.162 + 18.163 +/* OpenGL helper functions */ 18.164 + 18.165 +/* Returns the equivalent OpenGL "format" as expected by the 7th argument of glTexImage2D */ 18.166 +unsigned int img_fmt_glfmt(enum img_fmt fmt); 18.167 +/* Returns the equivalent OpenGL "type" as expected by the 8th argument of glTexImage2D */ 18.168 +unsigned int img_fmt_gltype(enum img_fmt fmt); 18.169 +/* Returns the equivalent OpenGL "internal format" as expected by the 3rd argument of glTexImage2D */ 18.170 +unsigned int img_fmt_glintfmt(enum img_fmt fmt); 18.171 + 18.172 +/* Same as above, based on the pixel format of the supplied image */ 18.173 +unsigned int img_glfmt(struct img_pixmap *img); 18.174 +unsigned int img_gltype(struct img_pixmap *img); 18.175 +unsigned int img_glintfmt(struct img_pixmap *img); 18.176 + 18.177 +/* Creates an OpenGL texture from the image, and returns the texture id, or 0 for failure */ 18.178 +unsigned int img_gltexture(struct img_pixmap *img); 18.179 + 18.180 +/* Load an image and create an OpenGL texture out of it */ 18.181 +unsigned int img_gltexture_load(const char *fname); 18.182 +unsigned int img_gltexture_read_file(FILE *fp); 18.183 +unsigned int img_gltexture_read(struct img_io *io); 18.184 + 18.185 +/* These functions can be used to fill an img_io struct before it's passed to 18.186 + * one of the user-defined i/o image reading/writing functions (img_read/img_write). 18.187 + * 18.188 + * User-defined i/o functions: 18.189 + * 18.190 + * - size_t read_func(void *buffer, size_t bytes, void *user_ptr) 18.191 + * Must try to fill the buffer with the specified number of bytes, and return 18.192 + * the number of bytes actually read. 18.193 + * 18.194 + * - size_t write_func(void *buffer, size_t bytes, void *user_ptr) 18.195 + * Must write the specified number of bytes from the supplied buffer and return 18.196 + * the number of bytes actually written. 18.197 + * 18.198 + * - long seek_func(long offset, int whence, void *user_ptr) 18.199 + * Must seek offset bytes from: the beginning of the file if whence is SEEK_SET, 18.200 + * the current position if whence is SEEK_CUR, or the end of the file if whence is 18.201 + * SEEK_END, and return the resulting file offset from the beginning of the file. 18.202 + * (i.e. seek_func(0, SEEK_CUR, user_ptr); must be equivalent to an ftell). 18.203 + * 18.204 + * All three functions get the user-data pointer set through img_io_set_user_data 18.205 + * as their last argument. 18.206 + * 18.207 + * Note: obviously you don't need to set a write function if you're only going 18.208 + * to call img_read, or the read and seek function if you're only going to call 18.209 + * img_write. 18.210 + * 18.211 + * Note: if the user-supplied write function is buffered, make sure to flush 18.212 + * (or close the file) after img_write returns. 18.213 + */ 18.214 +void img_io_set_user_data(struct img_io *io, void *uptr); 18.215 +void img_io_set_read_func(struct img_io *io, size_t (*read)(void*, size_t, void*)); 18.216 +void img_io_set_write_func(struct img_io *io, size_t (*write)(void*, size_t, void*)); 18.217 +void img_io_set_seek_func(struct img_io *io, long (*seek)(long, int, void*)); 18.218 + 18.219 + 18.220 +#ifdef __cplusplus 18.221 +} 18.222 +#endif 18.223 + 18.224 + 18.225 +#endif /* IMAGO_H_ */
19.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 19.2 +++ b/prototype/imago2/imago_gl.c Sun Oct 07 02:04:00 2012 +0300 19.3 @@ -0,0 +1,223 @@ 19.4 +#include "imago2.h" 19.5 + 19.6 + 19.7 +/* to avoid dependency to OpenGL, I'll define all the relevant GL macros manually */ 19.8 +#define GL_UNSIGNED_BYTE 0x1401 19.9 +#define GL_FLOAT 0x1406 19.10 + 19.11 +#define GL_LUMINANCE 0x1909 19.12 +#define GL_RGB 0x1907 19.13 +#define GL_RGBA 0x1908 19.14 + 19.15 +#define GL_RGBA32F 0x8814 19.16 +#define GL_RGB32F 0x8815 19.17 +#define GL_LUMINANCE32F 0x8818 19.18 + 19.19 +#define GL_TEXTURE_2D 0x0de1 19.20 +#define GL_TEXTURE_WRAP_S 0x2802 19.21 +#define GL_TEXTURE_WRAP_T 0x2803 19.22 +#define GL_TEXTURE_MAG_FILTER 0x2800 19.23 +#define GL_TEXTURE_MIN_FILTER 0x2801 19.24 +#define GL_LINEAR 0x2601 19.25 +#define GL_REPEAT 0x2901 19.26 + 19.27 + 19.28 +typedef unsigned int GLenum; 19.29 +typedef unsigned int GLuint; 19.30 +typedef int GLint; 19.31 +typedef int GLsizei; 19.32 +typedef void GLvoid; 19.33 + 19.34 +/* for the same reason I'll load GL functions dynamically */ 19.35 +typedef void (*gl_gen_textures_func)(GLsizei, GLuint*); 19.36 +typedef void (*gl_bind_texture_func)(GLenum, GLuint); 19.37 +typedef void (*gl_tex_parameteri_func)(GLenum, GLenum, GLint); 19.38 +typedef void (*gl_tex_image2d_func)(GLenum, GLint, GLint, GLsizei, GLsizei, GLint, GLenum, GLenum, const GLvoid*); 19.39 + 19.40 +static gl_gen_textures_func gl_gen_textures; 19.41 +static gl_bind_texture_func gl_bind_texture; 19.42 +static gl_tex_parameteri_func gl_tex_parameteri; 19.43 +static gl_tex_image2d_func gl_tex_image2d; 19.44 + 19.45 +static int load_glfunc(void); 19.46 + 19.47 +unsigned int img_fmt_glfmt(enum img_fmt fmt) 19.48 +{ 19.49 + switch(fmt) { 19.50 + case IMG_FMT_GREY8: 19.51 + case IMG_FMT_GREYF: 19.52 + return GL_LUMINANCE; 19.53 + 19.54 + case IMG_FMT_RGB24: 19.55 + case IMG_FMT_RGBF: 19.56 + return GL_RGB; 19.57 + 19.58 + case IMG_FMT_RGBA32: 19.59 + case IMG_FMT_RGBAF: 19.60 + return GL_RGBA; 19.61 + 19.62 + default: 19.63 + break; 19.64 + } 19.65 + return 0; 19.66 +} 19.67 + 19.68 +unsigned int img_fmt_gltype(enum img_fmt fmt) 19.69 +{ 19.70 + switch(fmt) { 19.71 + case IMG_FMT_GREY8: 19.72 + case IMG_FMT_RGB24: 19.73 + case IMG_FMT_RGBA32: 19.74 + return GL_UNSIGNED_BYTE; 19.75 + 19.76 + case IMG_FMT_GREYF: 19.77 + case IMG_FMT_RGBF: 19.78 + case IMG_FMT_RGBAF: 19.79 + return GL_FLOAT; 19.80 + 19.81 + default: 19.82 + break; 19.83 + } 19.84 + return 0; 19.85 +} 19.86 + 19.87 +unsigned int img_fmt_glintfmt(enum img_fmt fmt) 19.88 +{ 19.89 + switch(fmt) { 19.90 + case IMG_FMT_GREY8: 19.91 + return GL_LUMINANCE; 19.92 + case IMG_FMT_RGB24: 19.93 + return GL_RGB; 19.94 + case IMG_FMT_RGBA32: 19.95 + return GL_RGBA; 19.96 + case IMG_FMT_GREYF: 19.97 + return GL_LUMINANCE32F; 19.98 + case IMG_FMT_RGBF: 19.99 + return GL_RGB32F; 19.100 + case IMG_FMT_RGBAF: 19.101 + return GL_RGBA32F; 19.102 + default: 19.103 + break; 19.104 + } 19.105 + return 0; 19.106 +} 19.107 + 19.108 +unsigned int img_glfmt(struct img_pixmap *img) 19.109 +{ 19.110 + return img_fmt_glfmt(img->fmt); 19.111 +} 19.112 + 19.113 +unsigned int img_gltype(struct img_pixmap *img) 19.114 +{ 19.115 + return img_fmt_gltype(img->fmt); 19.116 +} 19.117 + 19.118 +unsigned int img_glintfmt(struct img_pixmap *img) 19.119 +{ 19.120 + return img_fmt_glintfmt(img->fmt); 19.121 +} 19.122 + 19.123 +unsigned int img_gltexture(struct img_pixmap *img) 19.124 +{ 19.125 + unsigned int tex; 19.126 + unsigned int intfmt, fmt, type; 19.127 + 19.128 + if(!gl_gen_textures) { 19.129 + if(load_glfunc() == -1) { 19.130 + fprintf(stderr, "imago: failed to initialize the OpenGL helpers\n"); 19.131 + return 0; 19.132 + } 19.133 + } 19.134 + 19.135 + intfmt = img_glintfmt(img); 19.136 + fmt = img_glfmt(img); 19.137 + type = img_gltype(img); 19.138 + 19.139 + gl_gen_textures(1, &tex); 19.140 + gl_bind_texture(GL_TEXTURE_2D, tex); 19.141 + gl_tex_parameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); 19.142 + gl_tex_parameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); 19.143 + gl_tex_parameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); 19.144 + gl_tex_parameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); 19.145 + gl_tex_image2d(GL_TEXTURE_2D, 0, intfmt, img->width, img->height, 0, fmt, type, img->pixels); 19.146 + return tex; 19.147 +} 19.148 + 19.149 +unsigned int img_gltexture_load(const char *fname) 19.150 +{ 19.151 + struct img_pixmap img; 19.152 + unsigned int tex; 19.153 + 19.154 + img_init(&img); 19.155 + if(img_load(&img, fname) == -1) { 19.156 + img_destroy(&img); 19.157 + return 0; 19.158 + } 19.159 + 19.160 + tex = img_gltexture(&img); 19.161 + img_destroy(&img); 19.162 + return tex; 19.163 +} 19.164 + 19.165 +unsigned int img_gltexture_read_file(FILE *fp) 19.166 +{ 19.167 + struct img_pixmap img; 19.168 + unsigned int tex; 19.169 + 19.170 + img_init(&img); 19.171 + if(img_read_file(&img, fp) == -1) { 19.172 + img_destroy(&img); 19.173 + return 0; 19.174 + } 19.175 + 19.176 + tex = img_gltexture(&img); 19.177 + img_destroy(&img); 19.178 + return tex; 19.179 +} 19.180 + 19.181 +unsigned int img_gltexture_read(struct img_io *io) 19.182 +{ 19.183 + struct img_pixmap img; 19.184 + unsigned int tex; 19.185 + 19.186 + img_init(&img); 19.187 + if(img_read(&img, io) == -1) { 19.188 + img_destroy(&img); 19.189 + return 0; 19.190 + } 19.191 + 19.192 + tex = img_gltexture(&img); 19.193 + img_destroy(&img); 19.194 + return tex; 19.195 +} 19.196 + 19.197 +#if defined(__unix__) || defined(__APPLE__) 19.198 +#ifndef __USE_GNU 19.199 +#define __USE_GNU 19.200 +#endif 19.201 + 19.202 +#include <dlfcn.h> 19.203 +#endif 19.204 +#ifdef WIN32 19.205 +#include <windows.h> 19.206 +#endif 19.207 + 19.208 +static int load_glfunc(void) 19.209 +{ 19.210 +#if defined(__unix__) || defined(__APPLE__) 19.211 + gl_gen_textures = (gl_gen_textures_func)dlsym(RTLD_DEFAULT, "glGenTextures"); 19.212 + gl_bind_texture = (gl_bind_texture_func)dlsym(RTLD_DEFAULT, "glBindTexture"); 19.213 + gl_tex_parameteri = (gl_tex_parameteri_func)dlsym(RTLD_DEFAULT, "glTexParameteri"); 19.214 + gl_tex_image2d = (gl_tex_image2d_func)dlsym(RTLD_DEFAULT, "glTexImage2D"); 19.215 +#endif 19.216 + 19.217 +#ifdef WIN32 19.218 + HMODULE handle = GetModuleHandle(0); 19.219 + gl_gen_textures = (gl_gen_textures_func)GetProcAddress(handle, "glGenTextures"); 19.220 + gl_bind_texture = (gl_bind_texture_func)GetProcAddress(handle, "glBindTexture"); 19.221 + gl_tex_parameteri = (gl_tex_parameteri_func)GetProcAddress(handle, "glTexParameteri"); 19.222 + gl_tex_image2d = (gl_tex_image2d_func)GetProcAddress(handle, "glTexImage2D"); 19.223 +#endif 19.224 + 19.225 + return (gl_gen_textures && gl_bind_texture && gl_tex_parameteri && gl_tex_image2d) ? 0 : -1; 19.226 +}
20.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 20.2 +++ b/prototype/imago2/modules.c Sun Oct 07 02:04:00 2012 +0300 20.3 @@ -0,0 +1,13 @@ 20.4 +/* this file is generated by ./configure, do not edit */ 20.5 +int img_register_jpeg(); 20.6 +int img_register_png(); 20.7 +int img_register_ppm(); 20.8 +int img_register_rgbe(); 20.9 + 20.10 +void img_modules_init(void) 20.11 +{ 20.12 + img_register_jpeg(); 20.13 + img_register_png(); 20.14 + img_register_ppm(); 20.15 + img_register_rgbe(); 20.16 +}
21.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 21.2 +++ b/prototype/psys/pattr.c Sun Oct 07 02:04:00 2012 +0300 21.3 @@ -0,0 +1,371 @@ 21.4 +#define _GNU_SOURCE 21.5 +#include <stdio.h> 21.6 +#include <stdlib.h> 21.7 +#include <string.h> 21.8 +#include <errno.h> 21.9 +#include <ctype.h> 21.10 + 21.11 +#ifdef _MSC_VER 21.12 +#include <malloc.h> 21.13 +#else 21.14 +#include <alloca.h> 21.15 +#endif 21.16 + 21.17 +#include "pattr.h" 21.18 +#include "psys_gl.h" 21.19 + 21.20 +enum { 21.21 + OPT_STR, 21.22 + OPT_NUM, 21.23 + OPT_NUM_RANGE, 21.24 + OPT_VEC, 21.25 + OPT_VEC_RANGE 21.26 +}; 21.27 + 21.28 +struct cfgopt { 21.29 + char *name; 21.30 + int type; 21.31 + long tm; 21.32 + char *valstr; 21.33 + vec3_t val, valrng; 21.34 +}; 21.35 + 21.36 +static int init_particle_attr(struct psys_particle_attributes *pattr); 21.37 +static void destroy_particle_attr(struct psys_particle_attributes *pattr); 21.38 +static struct cfgopt *get_cfg_opt(const char *line); 21.39 +static void release_cfg_opt(struct cfgopt *opt); 21.40 +static char *stripspace(char *str); 21.41 + 21.42 +static void *tex_cls; 21.43 +static unsigned int (*load_texture)(const char*, void*) = psys_gl_load_texture; 21.44 +static void (*unload_texture)(unsigned int, void*) = psys_gl_unload_texture; 21.45 + 21.46 + 21.47 +void psys_texture_loader(unsigned int (*load)(const char*, void*), void (*unload)(unsigned int, void*), void *cls) 21.48 +{ 21.49 + load_texture = load; 21.50 + unload_texture = unload; 21.51 + tex_cls = cls; 21.52 +} 21.53 + 21.54 +struct psys_attributes *psys_create_attr(void) 21.55 +{ 21.56 + struct psys_attributes *attr = malloc(sizeof *attr); 21.57 + if(attr) { 21.58 + if(psys_init_attr(attr) == -1) { 21.59 + free(attr); 21.60 + attr = 0; 21.61 + } 21.62 + } 21.63 + return attr; 21.64 +} 21.65 + 21.66 +void psys_free_attr(struct psys_attributes *attr) 21.67 +{ 21.68 + psys_destroy_attr(attr); 21.69 + free(attr); 21.70 +} 21.71 + 21.72 +int psys_init_attr(struct psys_attributes *attr) 21.73 +{ 21.74 + memset(attr, 0, sizeof *attr); 21.75 + 21.76 + if(psys_init_track3(&attr->spawn_range) == -1) 21.77 + goto err; 21.78 + if(psys_init_track(&attr->rate) == -1) 21.79 + goto err; 21.80 + if(psys_init_anm_rnd(&attr->life) == -1) 21.81 + goto err; 21.82 + if(psys_init_anm_rnd(&attr->size) == -1) 21.83 + goto err; 21.84 + if(psys_init_anm_rnd3(&attr->dir) == -1) 21.85 + goto err; 21.86 + if(psys_init_track3(&attr->grav) == -1) 21.87 + goto err; 21.88 + 21.89 + if(init_particle_attr(&attr->part_attr) == -1) 21.90 + goto err; 21.91 + 21.92 + attr->max_particles = -1; 21.93 + 21.94 + anm_set_track_default(&attr->size.value.trk, 1.0); 21.95 + anm_set_track_default(&attr->life.value.trk, 1.0); 21.96 + 21.97 + return 0; 21.98 + 21.99 +err: 21.100 + psys_destroy_attr(attr); 21.101 + return -1; 21.102 +} 21.103 + 21.104 + 21.105 +static int init_particle_attr(struct psys_particle_attributes *pattr) 21.106 +{ 21.107 + if(psys_init_track3(&pattr->color) == -1) { 21.108 + return -1; 21.109 + } 21.110 + if(psys_init_track(&pattr->alpha) == -1) { 21.111 + psys_destroy_track3(&pattr->color); 21.112 + return -1; 21.113 + } 21.114 + if(psys_init_track(&pattr->size) == -1) { 21.115 + psys_destroy_track3(&pattr->color); 21.116 + psys_destroy_track(&pattr->alpha); 21.117 + return -1; 21.118 + } 21.119 + 21.120 + anm_set_track_default(&pattr->color.x, 1.0); 21.121 + anm_set_track_default(&pattr->color.y, 1.0); 21.122 + anm_set_track_default(&pattr->color.z, 1.0); 21.123 + anm_set_track_default(&pattr->alpha.trk, 1.0); 21.124 + anm_set_track_default(&pattr->size.trk, 1.0); 21.125 + return 0; 21.126 +} 21.127 + 21.128 + 21.129 +void psys_destroy_attr(struct psys_attributes *attr) 21.130 +{ 21.131 + psys_destroy_track3(&attr->spawn_range); 21.132 + psys_destroy_track(&attr->rate); 21.133 + psys_destroy_anm_rnd(&attr->life); 21.134 + psys_destroy_anm_rnd(&attr->size); 21.135 + psys_destroy_anm_rnd3(&attr->dir); 21.136 + psys_destroy_track3(&attr->grav); 21.137 + 21.138 + destroy_particle_attr(&attr->part_attr); 21.139 + 21.140 + if(attr->tex && unload_texture) { 21.141 + unload_texture(attr->tex, tex_cls); 21.142 + } 21.143 +} 21.144 + 21.145 +static void destroy_particle_attr(struct psys_particle_attributes *pattr) 21.146 +{ 21.147 + psys_destroy_track3(&pattr->color); 21.148 + psys_destroy_track(&pattr->alpha); 21.149 + psys_destroy_track(&pattr->size); 21.150 +} 21.151 + 21.152 +void psys_eval_attr(struct psys_attributes *attr, anm_time_t tm) 21.153 +{ 21.154 + psys_eval_track3(&attr->spawn_range, tm); 21.155 + psys_eval_track(&attr->rate, tm); 21.156 + psys_eval_anm_rnd(&attr->life, tm); 21.157 + psys_eval_anm_rnd(&attr->size, tm); 21.158 + psys_eval_anm_rnd3(&attr->dir, tm); 21.159 + psys_eval_track3(&attr->grav, tm); 21.160 +} 21.161 + 21.162 +int psys_load_attr(struct psys_attributes *attr, const char *fname) 21.163 +{ 21.164 + FILE *fp; 21.165 + int res; 21.166 + 21.167 + if(!fname) { 21.168 + return -1; 21.169 + } 21.170 + 21.171 + if(!(fp = fopen(fname, "r"))) { 21.172 + fprintf(stderr, "%s: failed to read file: %s: %s\n", __func__, fname, strerror(errno)); 21.173 + return -1; 21.174 + } 21.175 + res = psys_load_attr_stream(attr, fp); 21.176 + fclose(fp); 21.177 + return res; 21.178 +} 21.179 + 21.180 +int psys_load_attr_stream(struct psys_attributes *attr, FILE *fp) 21.181 +{ 21.182 + int lineno = 0; 21.183 + char buf[512]; 21.184 + struct cfgopt *opt = 0; 21.185 + 21.186 + psys_init_attr(attr); 21.187 + 21.188 + while(fgets(buf, sizeof buf, fp)) { 21.189 + 21.190 + lineno++; 21.191 + 21.192 + if(!(opt = get_cfg_opt(buf))) { 21.193 + continue; 21.194 + } 21.195 + 21.196 + if(strcmp(opt->name, "texture") == 0) { 21.197 + if(opt->type != OPT_STR) { 21.198 + goto err; 21.199 + } 21.200 + if(!(attr->tex = load_texture(opt->valstr, tex_cls))) { 21.201 + fprintf(stderr, "failed to load texture: %s\n", opt->valstr); 21.202 + goto err; 21.203 + } 21.204 + 21.205 + release_cfg_opt(opt); 21.206 + continue; 21.207 + } else if(opt->type == OPT_STR) { 21.208 + fprintf(stderr, "invalid particle config: '%s'\n", opt->name); 21.209 + goto err; 21.210 + } 21.211 + 21.212 + if(strcmp(opt->name, "spawn_range") == 0) { 21.213 + psys_set_value3(&attr->spawn_range, opt->tm, opt->val); 21.214 + } else if(strcmp(opt->name, "rate") == 0) { 21.215 + psys_set_value(&attr->rate, opt->tm, opt->val.x); 21.216 + } else if(strcmp(opt->name, "life") == 0) { 21.217 + psys_set_anm_rnd(&attr->life, opt->tm, opt->val.x, opt->valrng.x); 21.218 + } else if(strcmp(opt->name, "size") == 0) { 21.219 + psys_set_anm_rnd(&attr->size, opt->tm, opt->val.x, opt->valrng.x); 21.220 + } else if(strcmp(opt->name, "dir") == 0) { 21.221 + psys_set_anm_rnd3(&attr->dir, opt->tm, opt->val, opt->valrng); 21.222 + } else if(strcmp(opt->name, "grav") == 0) { 21.223 + psys_set_value3(&attr->grav, opt->tm, opt->val); 21.224 + } else if(strcmp(opt->name, "drag") == 0) { 21.225 + attr->drag = opt->val.x; 21.226 + } else if(strcmp(opt->name, "pcolor") == 0) { 21.227 + psys_set_value3(&attr->part_attr.color, opt->tm, opt->val); 21.228 + } else if(strcmp(opt->name, "palpha") == 0) { 21.229 + psys_set_value(&attr->part_attr.alpha, opt->tm, opt->val.x); 21.230 + } else if(strcmp(opt->name, "psize") == 0) { 21.231 + psys_set_value(&attr->part_attr.size, opt->tm, opt->val.x); 21.232 + } else { 21.233 + fprintf(stderr, "unrecognized particle config option: %s\n", opt->name); 21.234 + goto err; 21.235 + } 21.236 + 21.237 + release_cfg_opt(opt); 21.238 + } 21.239 + 21.240 + return 0; 21.241 + 21.242 +err: 21.243 + fprintf(stderr, "Line %d: error parsing particle definition\n", lineno); 21.244 + release_cfg_opt(opt); 21.245 + return -1; 21.246 +} 21.247 + 21.248 +static struct cfgopt *get_cfg_opt(const char *line) 21.249 +{ 21.250 + char *buf, *tmp; 21.251 + struct cfgopt *opt; 21.252 + 21.253 + line = stripspace((char*)line); 21.254 + if(line[0] == '#' || !line[0]) { 21.255 + return 0; /* skip empty lines and comments */ 21.256 + } 21.257 + 21.258 + if(!(opt = malloc(sizeof *opt))) { 21.259 + return 0; 21.260 + } 21.261 + 21.262 + if(!(opt->valstr = strchr(line, '='))) { 21.263 + release_cfg_opt(opt); 21.264 + return 0; 21.265 + } 21.266 + *opt->valstr++ = 0; 21.267 + opt->valstr = stripspace(opt->valstr); 21.268 + 21.269 + /* allocate a working buffer on the stack that could fit the current line */ 21.270 + buf = alloca(strlen(line) + 1); 21.271 + strcpy(buf, line); 21.272 + buf = stripspace(buf); 21.273 + 21.274 + /* parse the keyframe time specifier if it exists */ 21.275 + if((tmp = strchr(buf, '('))) { 21.276 + char *endp; 21.277 + float tval; 21.278 + 21.279 + *tmp++ = 0; 21.280 + opt->name = strdup(buf); 21.281 + 21.282 + tval = strtod(tmp, &endp); 21.283 + if(endp == tmp) { /* nada ... */ 21.284 + opt->tm = 0; 21.285 + } else if(*endp == 's') { /* seconds suffix */ 21.286 + opt->tm = (long)(tval * 1000.0f); 21.287 + } else { 21.288 + opt->tm = (long)tval; 21.289 + } 21.290 + } else { 21.291 + opt->name = strdup(buf); 21.292 + opt->tm = 0; 21.293 + } 21.294 + 21.295 + if(sscanf(opt->valstr, "[%f %f %f] ~ [%f %f %f]", &opt->val.x, &opt->val.y, &opt->val.z, 21.296 + &opt->valrng.x, &opt->valrng.y, &opt->valrng.z) == 6) { 21.297 + /* value is a vector range */ 21.298 + opt->type = OPT_VEC_RANGE; 21.299 + 21.300 + } else if(sscanf(opt->valstr, "%f ~ %f", &opt->val.x, &opt->valrng.x) == 2) { 21.301 + /* value is a number range */ 21.302 + opt->type = OPT_NUM_RANGE; 21.303 + opt->val.y = opt->val.z = opt->val.x; 21.304 + opt->valrng.y = opt->valrng.z = opt->valrng.x; 21.305 + 21.306 + } else if(sscanf(opt->valstr, "[%f %f %f]", &opt->val.x, &opt->val.y, &opt->val.z) == 3) { 21.307 + /* value is a vector */ 21.308 + opt->type = OPT_VEC; 21.309 + opt->valrng.x = opt->valrng.y = opt->valrng.z = 0.0f; 21.310 + 21.311 + } else if(sscanf(opt->valstr, "%f", &opt->val.x) == 1) { 21.312 + /* value is a number */ 21.313 + opt->type = OPT_NUM; 21.314 + opt->val.y = opt->val.z = opt->val.x; 21.315 + opt->valrng.x = opt->valrng.y = opt->valrng.z = 0.0f; 21.316 + 21.317 + } else if(sscanf(opt->valstr, "\"%s\"", buf) == 1) { 21.318 + /* just a string... strip the quotes */ 21.319 + if(buf[strlen(buf) - 1] == '\"') { 21.320 + buf[strlen(buf) - 1] = 0; 21.321 + } 21.322 + opt->type = OPT_STR; 21.323 + opt->valstr = strdup(buf); 21.324 + } else { 21.325 + /* fuck it ... */ 21.326 + release_cfg_opt(opt); 21.327 + return 0; 21.328 + } 21.329 + 21.330 + return opt; 21.331 +} 21.332 + 21.333 +static void release_cfg_opt(struct cfgopt *opt) 21.334 +{ 21.335 + if(opt) { 21.336 + free(opt->name); 21.337 + } 21.338 +} 21.339 + 21.340 + 21.341 +int psys_save_attr(struct psys_attributes *attr, const char *fname) 21.342 +{ 21.343 + FILE *fp; 21.344 + int res; 21.345 + 21.346 + if(!(fp = fopen(fname, "w"))) { 21.347 + fprintf(stderr, "%s: failed to write file: %s: %s\n", __func__, fname, strerror(errno)); 21.348 + return -1; 21.349 + } 21.350 + res = psys_save_attr_stream(attr, fp); 21.351 + fclose(fp); 21.352 + return res; 21.353 +} 21.354 + 21.355 +int psys_save_attr_stream(struct psys_attributes *attr, FILE *fp) 21.356 +{ 21.357 + return -1; /* TODO */ 21.358 +} 21.359 + 21.360 + 21.361 +static char *stripspace(char *str) 21.362 +{ 21.363 + char *end; 21.364 + 21.365 + while(*str && isspace(*str)) { 21.366 + str++; 21.367 + } 21.368 + 21.369 + end = str + strlen(str) - 1; 21.370 + while(end >= str && isspace(*end)) { 21.371 + *end-- = 0; 21.372 + } 21.373 + return str; 21.374 +}
22.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 22.2 +++ b/prototype/psys/pattr.h Sun Oct 07 02:04:00 2012 +0300 22.3 @@ -0,0 +1,57 @@ 22.4 +#ifndef PATTR_H_ 22.5 +#define PATTR_H_ 22.6 + 22.7 +#include "pstrack.h" 22.8 +#include "rndval.h" 22.9 + 22.10 +/* the particle attributes vary from 0 to 1 during its lifetime */ 22.11 +struct psys_particle_attributes { 22.12 + struct psys_track3 color; 22.13 + struct psys_track alpha; 22.14 + struct psys_track size; 22.15 +}; 22.16 + 22.17 +struct psys_attributes { 22.18 + unsigned int tex; /* OpenGL texture to use for the billboard */ 22.19 + 22.20 + struct psys_track3 spawn_range; /* radius of emmiter */ 22.21 + struct psys_track rate; /* spawn rate particles per sec */ 22.22 + struct psys_anm_rnd life; /* particle life in seconds */ 22.23 + struct psys_anm_rnd size; /* base particle size */ 22.24 + struct psys_anm_rnd3 dir; /* particle shoot direction */ 22.25 + 22.26 + struct psys_track3 grav; /* external force (usually gravity) */ 22.27 + float drag; /* I don't think this needs to animate */ 22.28 + 22.29 + /* particle attributes */ 22.30 + struct psys_particle_attributes part_attr; 22.31 + 22.32 + /* limits */ 22.33 + int max_particles; 22.34 +}; 22.35 + 22.36 +#ifdef __cplusplus 22.37 +extern "C" { 22.38 +#endif 22.39 + 22.40 +void psys_texture_loader(unsigned int (*load)(const char*, void*), void (*unload)(unsigned int, void*), void *cls); 22.41 + 22.42 +struct psys_attributes *psys_create_attr(void); 22.43 +void psys_free_attr(struct psys_attributes *attr); 22.44 + 22.45 +int psys_init_attr(struct psys_attributes *attr); 22.46 +void psys_destroy_attr(struct psys_attributes *attr); 22.47 + 22.48 +void psys_eval_attr(struct psys_attributes *attr, anm_time_t tm); 22.49 + 22.50 +int psys_load_attr(struct psys_attributes *attr, const char *fname); 22.51 +int psys_load_attr_stream(struct psys_attributes *attr, FILE *fp); 22.52 + 22.53 +int psys_save_attr(struct psys_attributes *attr, const char *fname); 22.54 +int psys_save_attr_stream(struct psys_attributes *attr, FILE *fp); 22.55 + 22.56 +#ifdef __cplusplus 22.57 +} 22.58 +#endif 22.59 + 22.60 +#endif /* PATTR_H_ */
23.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 23.2 +++ b/prototype/psys/pstrack.c Sun Oct 07 02:04:00 2012 +0300 23.3 @@ -0,0 +1,97 @@ 23.4 +#include "pstrack.h" 23.5 + 23.6 +int psys_init_track(struct psys_track *track) 23.7 +{ 23.8 + track->cache_tm = ANM_TIME_INVAL; 23.9 + 23.10 + if(anm_init_track(&track->trk) == -1) { 23.11 + return -1; 23.12 + } 23.13 + return 0; 23.14 +} 23.15 + 23.16 +void psys_destroy_track(struct psys_track *track) 23.17 +{ 23.18 + anm_destroy_track(&track->trk); 23.19 +} 23.20 + 23.21 +int psys_init_track3(struct psys_track3 *track) 23.22 +{ 23.23 + track->cache_tm = ANM_TIME_INVAL; 23.24 + 23.25 + if(anm_init_track(&track->x) == -1) { 23.26 + return -1; 23.27 + } 23.28 + if(anm_init_track(&track->y) == -1) { 23.29 + anm_destroy_track(&track->x); 23.30 + return -1; 23.31 + } 23.32 + if(anm_init_track(&track->z) == -1) { 23.33 + anm_destroy_track(&track->x); 23.34 + anm_destroy_track(&track->z); 23.35 + return -1; 23.36 + } 23.37 + return 0; 23.38 +} 23.39 + 23.40 +void psys_destroy_track3(struct psys_track3 *track) 23.41 +{ 23.42 + anm_destroy_track(&track->x); 23.43 + anm_destroy_track(&track->y); 23.44 + anm_destroy_track(&track->z); 23.45 +} 23.46 + 23.47 +void psys_eval_track(struct psys_track *track, anm_time_t tm) 23.48 +{ 23.49 + if(track->cache_tm != tm) { 23.50 + track->cache_tm = tm; 23.51 + track->cache_val = anm_get_value(&track->trk, tm); 23.52 + } 23.53 +} 23.54 + 23.55 +void psys_set_value(struct psys_track *track, anm_time_t tm, float v) 23.56 +{ 23.57 + anm_set_value(&track->trk, tm, v); 23.58 + track->cache_tm = ANM_TIME_INVAL; 23.59 +} 23.60 + 23.61 +float psys_get_value(struct psys_track *track, anm_time_t tm) 23.62 +{ 23.63 + psys_eval_track(track, tm); 23.64 + return track->cache_val; 23.65 +} 23.66 + 23.67 +float psys_get_cur_value(struct psys_track *track) 23.68 +{ 23.69 + return track->cache_val; 23.70 +} 23.71 + 23.72 + 23.73 +void psys_eval_track3(struct psys_track3 *track, anm_time_t tm) 23.74 +{ 23.75 + if(track->cache_tm != tm) { 23.76 + track->cache_tm = tm; 23.77 + track->cache_vec.x = anm_get_value(&track->x, tm); 23.78 + track->cache_vec.y = anm_get_value(&track->y, tm); 23.79 + track->cache_vec.z = anm_get_value(&track->z, tm); 23.80 + } 23.81 +} 23.82 + 23.83 +void psys_set_value3(struct psys_track3 *track, anm_time_t tm, vec3_t v) 23.84 +{ 23.85 + anm_set_value(&track->x, tm, v.x); 23.86 + anm_set_value(&track->y, tm, v.y); 23.87 + anm_set_value(&track->z, tm, v.z); 23.88 + track->cache_tm = ANM_TIME_INVAL; 23.89 +} 23.90 + 23.91 +vec3_t psys_get_value3(struct psys_track3 *track, anm_time_t tm) 23.92 +{ 23.93 + psys_eval_track3(track, tm); 23.94 + return track->cache_vec; 23.95 +} 23.96 + 23.97 +vec3_t psys_get_cur_value3(struct psys_track3 *track) 23.98 +{ 23.99 + return track->cache_vec; 23.100 +}
24.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 24.2 +++ b/prototype/psys/pstrack.h Sun Oct 07 02:04:00 2012 +0300 24.3 @@ -0,0 +1,37 @@ 24.4 +#ifndef PSTRACK_H_ 24.5 +#define PSTRACK_H_ 24.6 + 24.7 +#include <vmath/vmath.h> 24.8 +#include <anim/anim.h> 24.9 + 24.10 +struct psys_track { 24.11 + struct anm_track trk; 24.12 + 24.13 + anm_time_t cache_tm; 24.14 + float cache_val; 24.15 +}; 24.16 + 24.17 +struct psys_track3 { 24.18 + struct anm_track x, y, z; 24.19 + 24.20 + anm_time_t cache_tm; 24.21 + vec3_t cache_vec; 24.22 +}; 24.23 + 24.24 +int psys_init_track(struct psys_track *track); 24.25 +void psys_destroy_track(struct psys_track *track); 24.26 + 24.27 +int psys_init_track3(struct psys_track3 *track); 24.28 +void psys_destroy_track3(struct psys_track3 *track); 24.29 + 24.30 +void psys_eval_track(struct psys_track *track, anm_time_t tm); 24.31 +void psys_set_value(struct psys_track *track, anm_time_t tm, float v); 24.32 +float psys_get_value(struct psys_track *track, anm_time_t tm); 24.33 +float psys_get_cur_value(struct psys_track *track); 24.34 + 24.35 +void psys_eval_track3(struct psys_track3 *track, anm_time_t tm); 24.36 +void psys_set_value3(struct psys_track3 *track, anm_time_t tm, vec3_t v); 24.37 +vec3_t psys_get_value3(struct psys_track3 *track, anm_time_t tm); 24.38 +vec3_t psys_get_cur_value3(struct psys_track3 *track); 24.39 + 24.40 +#endif /* PSTRACK_H_ */
25.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 25.2 +++ b/prototype/psys/psys.c Sun Oct 07 02:04:00 2012 +0300 25.3 @@ -0,0 +1,325 @@ 25.4 +#include <stdlib.h> 25.5 +#include <math.h> 25.6 +#include <assert.h> 25.7 +#include <pthread.h> 25.8 +#include "psys.h" 25.9 +#include "psys_gl.h" 25.10 + 25.11 +static int spawn(struct psys_emitter *em, struct psys_particle *p, void *cls); 25.12 +static void update_particle(struct psys_emitter *em, struct psys_particle *p, float tm, float dt, void *cls); 25.13 + 25.14 +/* particle pool */ 25.15 +static struct psys_particle *ppool; 25.16 +static int ppool_size; 25.17 +static pthread_mutex_t pool_lock = PTHREAD_MUTEX_INITIALIZER; 25.18 + 25.19 +static struct psys_particle *palloc(void); 25.20 +static void pfree(struct psys_particle *p); 25.21 + 25.22 +/* --- constructors and shit --- */ 25.23 + 25.24 +struct psys_emitter *psys_create(void) 25.25 +{ 25.26 + struct psys_emitter *em; 25.27 + 25.28 + if(!(em = malloc(sizeof *em))) { 25.29 + return 0; 25.30 + } 25.31 + if(psys_init(em) == -1) { 25.32 + free(em); 25.33 + return 0; 25.34 + } 25.35 + return em; 25.36 +} 25.37 + 25.38 +void psys_free(struct psys_emitter *em) 25.39 +{ 25.40 + psys_destroy(em); 25.41 + free(em); 25.42 +} 25.43 + 25.44 +int psys_init(struct psys_emitter *em) 25.45 +{ 25.46 + memset(em, 0, sizeof *em); 25.47 + 25.48 + if(anm_init_node(&em->prs) == -1) { 25.49 + return -1; 25.50 + } 25.51 + if(psys_init_attr(&em->attr) == -1) { 25.52 + anm_destroy_node(&em->prs); 25.53 + return -1; 25.54 + } 25.55 + 25.56 + em->spawn = spawn; 25.57 + em->update = update_particle; 25.58 + 25.59 + em->draw = psys_gl_draw; 25.60 + em->draw_start = psys_gl_draw_start; 25.61 + em->draw_end = psys_gl_draw_end; 25.62 + return 0; 25.63 +} 25.64 + 25.65 +void psys_destroy(struct psys_emitter *em) 25.66 +{ 25.67 + struct psys_particle *part; 25.68 + 25.69 + part = em->plist; 25.70 + while(part) { 25.71 + struct psys_particle *tmp = part; 25.72 + part = part->next; 25.73 + pfree(tmp); 25.74 + } 25.75 + 25.76 + psys_destroy_attr(&em->attr); 25.77 +} 25.78 + 25.79 +void psys_set_pos(struct psys_emitter *em, vec3_t pos, float tm) 25.80 +{ 25.81 + anm_set_position(&em->prs, pos, ANM_SEC2TM(tm)); 25.82 +} 25.83 + 25.84 +void psys_set_rot(struct psys_emitter *em, quat_t rot, float tm) 25.85 +{ 25.86 + anm_set_rotation(&em->prs, rot, ANM_SEC2TM(tm)); 25.87 +} 25.88 + 25.89 +void psys_set_pivot(struct psys_emitter *em, vec3_t pivot) 25.90 +{ 25.91 + anm_set_pivot(&em->prs, pivot); 25.92 +} 25.93 + 25.94 +vec3_t psys_get_pos(struct psys_emitter *em, float tm) 25.95 +{ 25.96 + return anm_get_node_position(&em->prs, ANM_SEC2TM(tm)); 25.97 +} 25.98 + 25.99 +quat_t psys_get_rot(struct psys_emitter *em, float tm) 25.100 +{ 25.101 + return anm_get_node_rotation(&em->prs, ANM_SEC2TM(tm)); 25.102 +} 25.103 + 25.104 +vec3_t psys_get_pivot(struct psys_emitter *em) 25.105 +{ 25.106 + return anm_get_pivot(&em->prs); 25.107 +} 25.108 + 25.109 +void psys_clear_collision_planes(struct psys_emitter *em) 25.110 +{ 25.111 + struct psys_plane *plane; 25.112 + 25.113 + plane = em->planes; 25.114 + while(plane) { 25.115 + struct psys_plane *tmp = plane; 25.116 + plane = plane->next; 25.117 + free(tmp); 25.118 + } 25.119 +} 25.120 + 25.121 +int psys_add_collision_plane(struct psys_emitter *em, plane_t plane, float elast) 25.122 +{ 25.123 + struct psys_plane *node; 25.124 + 25.125 + if(!(node = malloc(sizeof *node))) { 25.126 + return -1; 25.127 + } 25.128 + node->p = plane; 25.129 + node->elasticity = elast; 25.130 + node->next = em->planes; 25.131 + em->planes = node; 25.132 + return 0; 25.133 +} 25.134 + 25.135 +void psys_add_particle(struct psys_emitter *em, struct psys_particle *p) 25.136 +{ 25.137 + p->next = em->plist; 25.138 + em->plist = p; 25.139 + 25.140 + em->pcount++; 25.141 +} 25.142 + 25.143 +void psys_spawn_func(struct psys_emitter *em, psys_spawn_func_t func, void *cls) 25.144 +{ 25.145 + em->spawn = func; 25.146 + em->spawn_cls = cls; 25.147 +} 25.148 + 25.149 +void psys_update_func(struct psys_emitter *em, psys_update_func_t func, void *cls) 25.150 +{ 25.151 + em->update = func; 25.152 + em->upd_cls = cls; 25.153 +} 25.154 + 25.155 +void psys_draw_func(struct psys_emitter *em, psys_draw_func_t draw, 25.156 + psys_draw_start_func_t start, psys_draw_end_func_t end, void *cls) 25.157 +{ 25.158 + em->draw = draw; 25.159 + em->draw_start = start; 25.160 + em->draw_end = end; 25.161 + em->draw_cls = cls; 25.162 +} 25.163 + 25.164 +/* --- update and render --- */ 25.165 + 25.166 +void psys_update(struct psys_emitter *em, float tm) 25.167 +{ 25.168 + float dt, spawn_dt, spawn_tm; 25.169 + int i, spawn_count; 25.170 + struct psys_particle *p, pdummy; 25.171 + anm_time_t atm = ANM_SEC2TM(tm); 25.172 + 25.173 + assert(em->spawn && em->update); 25.174 + 25.175 + dt = tm - em->last_update; 25.176 + if(dt <= 0.0) { 25.177 + return; 25.178 + } 25.179 + 25.180 + psys_eval_attr(&em->attr, atm); 25.181 + 25.182 + /* how many particles to spawn for this interval ? */ 25.183 + em->spawn_acc += psys_get_cur_value(&em->attr.rate) * dt; 25.184 + if(em->spawn_acc >= 1.0) { 25.185 + spawn_count = em->spawn_acc; 25.186 + em->spawn_acc = fmod(em->spawn_acc, 1.0); 25.187 + } else { 25.188 + spawn_count = 0; 25.189 + } 25.190 + 25.191 + spawn_dt = dt / (float)spawn_count; 25.192 + spawn_tm = em->last_update; 25.193 + for(i=0; i<spawn_count; i++) { 25.194 + if(em->attr.max_particles >= 0 && em->pcount >= em->attr.max_particles) { 25.195 + break; 25.196 + } 25.197 + 25.198 + /* update emitter position for this spawning */ 25.199 + em->cur_pos = anm_get_position(&em->prs, ANM_SEC2TM(spawn_tm)); 25.200 + 25.201 + if(!(p = palloc())) { 25.202 + return; 25.203 + } 25.204 + if(em->spawn(em, p, em->spawn_cls) == -1) { 25.205 + pfree(p); 25.206 + } 25.207 + spawn_tm += spawn_dt; 25.208 + } 25.209 + 25.210 + /* update all particles */ 25.211 + p = em->plist; 25.212 + while(p) { 25.213 + em->update(em, p, tm, dt, em->upd_cls); 25.214 + p = p->next; 25.215 + } 25.216 + 25.217 + /* cleanup dead particles */ 25.218 + pdummy.next = em->plist; 25.219 + p = &pdummy; 25.220 + while(p->next) { 25.221 + if(p->next->life <= 0) { 25.222 + struct psys_particle *tmp = p->next; 25.223 + p->next = p->next->next; 25.224 + pfree(tmp); 25.225 + em->pcount--; 25.226 + } else { 25.227 + p = p->next; 25.228 + } 25.229 + } 25.230 + em->plist = pdummy.next; 25.231 + 25.232 + em->last_update = tm; 25.233 + 25.234 + /*printf("particles: %5d\r", em->pcount);*/ 25.235 +} 25.236 + 25.237 +void psys_draw(struct psys_emitter *em) 25.238 +{ 25.239 + struct psys_particle *p; 25.240 + 25.241 + if(em->draw_start) { 25.242 + em->draw_start(em, em->draw_cls); 25.243 + } 25.244 + 25.245 + p = em->plist; 25.246 + while(p) { 25.247 + em->draw(em, p, em->draw_cls); 25.248 + p = p->next; 25.249 + } 25.250 + 25.251 + if(em->draw_end) { 25.252 + em->draw_end(em, em->draw_cls); 25.253 + } 25.254 +} 25.255 + 25.256 +static int spawn(struct psys_emitter *em, struct psys_particle *p, void *cls) 25.257 +{ 25.258 + struct psys_rnd3 rpos; 25.259 + rpos.value = em->cur_pos; 25.260 + rpos.range = psys_get_cur_value3(&em->attr.spawn_range); 25.261 + 25.262 + p->pos = psys_eval_rnd3(&rpos); 25.263 + p->vel = psys_eval_anm_rnd3(&em->attr.dir, PSYS_EVAL_CUR); 25.264 + p->base_size = psys_eval_anm_rnd(&em->attr.size, PSYS_EVAL_CUR); 25.265 + p->max_life = p->life = psys_eval_anm_rnd(&em->attr.life, PSYS_EVAL_CUR); 25.266 + 25.267 + p->pattr = &em->attr.part_attr; 25.268 + 25.269 + psys_add_particle(em, p); 25.270 + return 0; 25.271 +} 25.272 + 25.273 +static void update_particle(struct psys_emitter *em, struct psys_particle *p, float tm, float dt, void *cls) 25.274 +{ 25.275 + vec3_t accel, grav; 25.276 + anm_time_t t; 25.277 + 25.278 + grav = psys_get_cur_value3(&em->attr.grav); 25.279 + 25.280 + accel.x = grav.x - p->vel.x * em->attr.drag; 25.281 + accel.y = grav.y - p->vel.y * em->attr.drag; 25.282 + accel.z = grav.z - p->vel.z * em->attr.drag; 25.283 + 25.284 + p->vel.x += accel.x * dt; 25.285 + p->vel.y += accel.y * dt; 25.286 + p->vel.z += accel.z * dt; 25.287 + 25.288 + p->pos.x += p->vel.x * dt; 25.289 + p->pos.y += p->vel.y * dt; 25.290 + p->pos.z += p->vel.z * dt; 25.291 + 25.292 + /* update particle attributes */ 25.293 + t = (anm_time_t)(1000.0 * (p->max_life - p->life) / p->max_life); 25.294 + 25.295 + p->color = psys_get_value3(&p->pattr->color, t); 25.296 + p->alpha = psys_get_value(&p->pattr->alpha, t); 25.297 + p->size = p->base_size * psys_get_value(&p->pattr->size, t); 25.298 + 25.299 + p->life -= dt; 25.300 +} 25.301 + 25.302 +/* --- particle allocation pool --- */ 25.303 + 25.304 +static struct psys_particle *palloc(void) 25.305 +{ 25.306 + struct psys_particle *p; 25.307 + 25.308 + pthread_mutex_lock(&pool_lock); 25.309 + if(ppool) { 25.310 + p = ppool; 25.311 + ppool = ppool->next; 25.312 + ppool_size--; 25.313 + } else { 25.314 + p = malloc(sizeof *p); 25.315 + } 25.316 + pthread_mutex_unlock(&pool_lock); 25.317 + 25.318 + return p; 25.319 +} 25.320 + 25.321 +static void pfree(struct psys_particle *p) 25.322 +{ 25.323 + pthread_mutex_lock(&pool_lock); 25.324 + p->next = ppool; 25.325 + ppool = p; 25.326 + ppool_size++; 25.327 + pthread_mutex_unlock(&pool_lock); 25.328 +}
26.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 26.2 +++ b/prototype/psys/psys.h Sun Oct 07 02:04:00 2012 +0300 26.3 @@ -0,0 +1,111 @@ 26.4 +#ifndef LIBPSYS_H_ 26.5 +#define LIBPSYS_H_ 26.6 + 26.7 +#include <vmath/vmath.h> 26.8 +#include <anim/anim.h> 26.9 +#include "rndval.h" 26.10 +#include "pattr.h" 26.11 + 26.12 +struct psys_particle; 26.13 +struct psys_emitter; 26.14 + 26.15 +typedef int (*psys_spawn_func_t)(struct psys_emitter*, struct psys_particle*, void*); 26.16 +typedef void (*psys_update_func_t)(struct psys_emitter*, struct psys_particle*, float, float, void*); 26.17 + 26.18 +typedef void (*psys_draw_func_t)(struct psys_emitter*, struct psys_particle*, void*); 26.19 +typedef void (*psys_draw_start_func_t)(struct psys_emitter*, void*); 26.20 +typedef void (*psys_draw_end_func_t)(struct psys_emitter*, void*); 26.21 + 26.22 + 26.23 +struct psys_plane { 26.24 + plane_t p; 26.25 + float elasticity; 26.26 + struct psys_plane *next; 26.27 +}; 26.28 + 26.29 + 26.30 +struct psys_emitter { 26.31 + struct anm_node prs; 26.32 + vec3_t cur_pos; 26.33 + 26.34 + struct psys_attributes attr; 26.35 + 26.36 + /* list of active particles */ 26.37 + struct psys_particle *plist; 26.38 + int pcount; /* number of active particles */ 26.39 + 26.40 + /* list of collision planes */ 26.41 + struct psys_plane *planes; 26.42 + 26.43 + /* custom spawn closure */ 26.44 + void *spawn_cls; 26.45 + psys_spawn_func_t spawn; 26.46 + 26.47 + /* custom particle update closure */ 26.48 + void *upd_cls; 26.49 + psys_update_func_t update; 26.50 + 26.51 + /* custom draw closure */ 26.52 + void *draw_cls; 26.53 + psys_draw_func_t draw; 26.54 + psys_draw_start_func_t draw_start; 26.55 + psys_draw_end_func_t draw_end; 26.56 + 26.57 + float spawn_acc; /* partial spawn accumulator */ 26.58 + float last_update; /* last update time (to calc dt) */ 26.59 +}; 26.60 + 26.61 + 26.62 +struct psys_particle { 26.63 + vec3_t pos, vel; 26.64 + float life, max_life; 26.65 + float base_size; 26.66 + 26.67 + struct psys_particle_attributes *pattr; 26.68 + 26.69 + /* current particle attr values calculated during update */ 26.70 + vec3_t color; 26.71 + float alpha, size; 26.72 + 26.73 + struct psys_particle *next; 26.74 +}; 26.75 + 26.76 +#ifdef __cplusplus 26.77 +extern "C" { 26.78 +#endif 26.79 + 26.80 +struct psys_emitter *psys_create(void); 26.81 +void psys_free(struct psys_emitter *em); 26.82 + 26.83 +int psys_init(struct psys_emitter *em); 26.84 +void psys_destroy(struct psys_emitter *em); 26.85 + 26.86 +/* set properties */ 26.87 +void psys_set_pos(struct psys_emitter *em, vec3_t pos, float tm); 26.88 +void psys_set_rot(struct psys_emitter *em, quat_t rot, float tm); 26.89 +void psys_set_pivot(struct psys_emitter *em, vec3_t pivot); 26.90 + 26.91 +vec3_t psys_get_pos(struct psys_emitter *em, float tm); 26.92 +quat_t psys_get_rot(struct psys_emitter *em, float tm); 26.93 +vec3_t psys_get_pivot(struct psys_emitter *em); 26.94 + 26.95 +void psys_clear_collision_planes(struct psys_emitter *em); 26.96 +int psys_add_collision_plane(struct psys_emitter *em, plane_t plane, float elast); 26.97 + 26.98 +void psys_add_particle(struct psys_emitter *em, struct psys_particle *p); 26.99 + 26.100 +void psys_spawn_func(struct psys_emitter *em, psys_spawn_func_t func, void *cls); 26.101 +void psys_update_func(struct psys_emitter *em, psys_update_func_t func, void *cls); 26.102 +void psys_draw_func(struct psys_emitter *em, psys_draw_func_t draw, 26.103 + psys_draw_start_func_t start, psys_draw_end_func_t end, void *cls); 26.104 + 26.105 +/* update and render */ 26.106 + 26.107 +void psys_update(struct psys_emitter *em, float tm); 26.108 +void psys_draw(struct psys_emitter *em); 26.109 + 26.110 +#ifdef __cplusplus 26.111 +} 26.112 +#endif 26.113 + 26.114 +#endif /* LIBPSYS_H_ */
27.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 27.2 +++ b/prototype/psys/psys_gl.c Sun Oct 07 02:04:00 2012 +0300 27.3 @@ -0,0 +1,106 @@ 27.4 +#include <string.h> 27.5 +#include <errno.h> 27.6 +#include <assert.h> 27.7 + 27.8 +#ifndef __APPLE__ 27.9 +#ifdef WIN32 27.10 +#include <windows.h> 27.11 +#endif 27.12 + 27.13 +#include <GL/gl.h> 27.14 +#else 27.15 +#include <OpenGL/gl.h> 27.16 +#endif 27.17 + 27.18 +#include <imago2.h> 27.19 +#include "psys.h" 27.20 +#include "psys_gl.h" 27.21 + 27.22 +void psys_gl_draw_start(struct psys_emitter *em, void *cls) 27.23 +{ 27.24 + glPushAttrib(GL_ENABLE_BIT); 27.25 + glDisable(GL_LIGHTING); 27.26 + 27.27 + glEnable(GL_BLEND); 27.28 + glBlendFunc(GL_SRC_ALPHA, GL_ONE); 27.29 + 27.30 + if(em->attr.tex) { 27.31 + glEnable(GL_TEXTURE_2D); 27.32 + glBindTexture(GL_TEXTURE_2D, em->attr.tex); 27.33 + } 27.34 + 27.35 + glDepthMask(0); 27.36 +} 27.37 + 27.38 +void psys_gl_draw(struct psys_emitter *em, struct psys_particle *p, void *cls) 27.39 +{ 27.40 + float hsz = p->size / 2.0; 27.41 + 27.42 + float xform[16]; 27.43 + 27.44 + glMatrixMode(GL_MODELVIEW); 27.45 + glPushMatrix(); 27.46 + 27.47 + glTranslatef(p->pos.x, p->pos.y, p->pos.z); 27.48 + 27.49 + glGetFloatv(GL_MODELVIEW_MATRIX, xform); 27.50 + xform[0] = xform[5] = xform[10] = 1.0; 27.51 + xform[1] = xform[2] = xform[4] = xform[6] = xform[8] = xform[9] = 0.0; 27.52 + glLoadMatrixf(xform); 27.53 + 27.54 + glBegin(GL_QUADS); 27.55 + glColor4f(p->color.x, p->color.y, p->color.z, p->alpha); 27.56 + 27.57 + glTexCoord2f(0, 0); 27.58 + glVertex2f(-hsz, -hsz); 27.59 + 27.60 + glTexCoord2f(1, 0); 27.61 + glVertex2f(hsz, -hsz); 27.62 + 27.63 + glTexCoord2f(1, 1); 27.64 + glVertex2f(hsz, hsz); 27.65 + 27.66 + glTexCoord2f(0, 1); 27.67 + glVertex2f(-hsz, hsz); 27.68 + glEnd(); 27.69 + 27.70 + glMatrixMode(GL_MODELVIEW); 27.71 + glPopMatrix(); 27.72 +} 27.73 + 27.74 +void psys_gl_draw_end(struct psys_emitter *em, void *cls) 27.75 +{ 27.76 + glDepthMask(1); 27.77 + glPopAttrib(); 27.78 +} 27.79 + 27.80 + 27.81 +unsigned int psys_gl_load_texture(const char *fname, void *cls) 27.82 +{ 27.83 + unsigned int tex; 27.84 + void *pixels; 27.85 + int xsz, ysz; 27.86 + 27.87 + if(!(pixels = img_load_pixels(fname, &xsz, &ysz, IMG_FMT_RGBA32))) { 27.88 + return 0; 27.89 + } 27.90 + printf("%s: creating texture %s (%dx%d)\n", __func__, fname, xsz, ysz); 27.91 + 27.92 + glGenTextures(1, &tex); 27.93 + glBindTexture(GL_TEXTURE_2D, tex); 27.94 + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); 27.95 + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); 27.96 + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP); 27.97 + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP); 27.98 + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, xsz, ysz, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixels); 27.99 + 27.100 + assert(glGetError() == GL_NO_ERROR); 27.101 + 27.102 + img_free_pixels(pixels); 27.103 + return tex; 27.104 +} 27.105 + 27.106 +void psys_gl_unload_texture(unsigned int tex, void *cls) 27.107 +{ 27.108 + glDeleteTextures(1, &tex); 27.109 +}
28.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 28.2 +++ b/prototype/psys/psys_gl.h Sun Oct 07 02:04:00 2012 +0300 28.3 @@ -0,0 +1,14 @@ 28.4 +#ifndef PSYS_GL_H_ 28.5 +#define PSYS_GL_H_ 28.6 + 28.7 +struct psys_particle; 28.8 +struct psys_emitter; 28.9 + 28.10 +void psys_gl_draw_start(struct psys_emitter *em, void *cls); 28.11 +void psys_gl_draw(struct psys_emitter *em, struct psys_particle *p, void *cls); 28.12 +void psys_gl_draw_end(struct psys_emitter *em, void *cls); 28.13 + 28.14 +unsigned int psys_gl_load_texture(const char *fname, void *cls); 28.15 +void psys_gl_unload_texture(unsigned int tex, void *cls); 28.16 + 28.17 +#endif /* PSYS_GL_H_ */
29.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 29.2 +++ b/prototype/psys/rndval.c Sun Oct 07 02:04:00 2012 +0300 29.3 @@ -0,0 +1,105 @@ 29.4 +#include <stdlib.h> 29.5 +#include "rndval.h" 29.6 + 29.7 +int psys_init_anm_rnd(struct psys_anm_rnd *r) 29.8 +{ 29.9 + if(psys_init_track(&r->value) == -1) { 29.10 + return -1; 29.11 + } 29.12 + if(psys_init_track(&r->range) == -1) { 29.13 + psys_destroy_track(&r->value); 29.14 + return -1; 29.15 + } 29.16 + return 0; 29.17 +} 29.18 + 29.19 +void psys_destroy_anm_rnd(struct psys_anm_rnd *r) 29.20 +{ 29.21 + psys_destroy_track(&r->value); 29.22 + psys_destroy_track(&r->range); 29.23 +} 29.24 + 29.25 +int psys_init_anm_rnd3(struct psys_anm_rnd3 *r) 29.26 +{ 29.27 + if(psys_init_track3(&r->value) == -1) { 29.28 + return -1; 29.29 + } 29.30 + if(psys_init_track3(&r->range) == -1) { 29.31 + psys_destroy_track3(&r->value); 29.32 + return -1; 29.33 + } 29.34 + return 0; 29.35 +} 29.36 + 29.37 +void psys_destroy_anm_rnd3(struct psys_anm_rnd3 *r) 29.38 +{ 29.39 + psys_destroy_track3(&r->value); 29.40 + psys_destroy_track3(&r->range); 29.41 +} 29.42 + 29.43 + 29.44 +void psys_set_rnd(struct psys_rnd *r, float val, float range) 29.45 +{ 29.46 + r->value = val; 29.47 + r->range = range; 29.48 +} 29.49 + 29.50 +void psys_set_rnd3(struct psys_rnd3 *r, vec3_t val, vec3_t range) 29.51 +{ 29.52 + r->value = val; 29.53 + r->range = range; 29.54 +} 29.55 + 29.56 +void psys_set_anm_rnd(struct psys_anm_rnd *r, anm_time_t tm, float val, float range) 29.57 +{ 29.58 + psys_set_value(&r->value, tm, val); 29.59 + psys_set_value(&r->range, tm, range); 29.60 +} 29.61 + 29.62 +void psys_set_anm_rnd3(struct psys_anm_rnd3 *r, anm_time_t tm, vec3_t val, vec3_t range) 29.63 +{ 29.64 + psys_set_value3(&r->value, tm, val); 29.65 + psys_set_value3(&r->range, tm, range); 29.66 +} 29.67 + 29.68 + 29.69 +float psys_eval_rnd(struct psys_rnd *r) 29.70 +{ 29.71 + return r->value + r->range * (float)rand() / (float)RAND_MAX - 0.5 * r->range; 29.72 +} 29.73 + 29.74 +vec3_t psys_eval_rnd3(struct psys_rnd3 *r) 29.75 +{ 29.76 + vec3_t res; 29.77 + res.x = r->value.x + r->range.x * (float)rand() / (float)RAND_MAX - 0.5 * r->range.x; 29.78 + res.y = r->value.y + r->range.y * (float)rand() / (float)RAND_MAX - 0.5 * r->range.y; 29.79 + res.z = r->value.z + r->range.z * (float)rand() / (float)RAND_MAX - 0.5 * r->range.z; 29.80 + return res; 29.81 +} 29.82 + 29.83 + 29.84 +float psys_eval_anm_rnd(struct psys_anm_rnd *r, anm_time_t tm) 29.85 +{ 29.86 + struct psys_rnd tmp; 29.87 + if(tm == ANM_TIME_INVAL) { 29.88 + tmp.value = psys_get_cur_value(&r->value); 29.89 + tmp.range = psys_get_cur_value(&r->range); 29.90 + } else { 29.91 + tmp.value = psys_get_value(&r->value, tm); 29.92 + tmp.range = psys_get_value(&r->range, tm); 29.93 + } 29.94 + return psys_eval_rnd(&tmp); 29.95 +} 29.96 + 29.97 +vec3_t psys_eval_anm_rnd3(struct psys_anm_rnd3 *r, anm_time_t tm) 29.98 +{ 29.99 + struct psys_rnd3 tmp; 29.100 + if(tm == ANM_TIME_INVAL) { 29.101 + tmp.value = psys_get_cur_value3(&r->value); 29.102 + tmp.range = psys_get_cur_value3(&r->range); 29.103 + } else { 29.104 + tmp.value = psys_get_value3(&r->value, tm); 29.105 + tmp.range = psys_get_value3(&r->range, tm); 29.106 + } 29.107 + return psys_eval_rnd3(&tmp); 29.108 +}
30.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 30.2 +++ b/prototype/psys/rndval.h Sun Oct 07 02:04:00 2012 +0300 30.3 @@ -0,0 +1,43 @@ 30.4 +#ifndef RNDVAL_H_ 30.5 +#define RNDVAL_H_ 30.6 + 30.7 +#include <vmath/vmath.h> 30.8 +#include "pstrack.h" 30.9 + 30.10 +struct psys_rnd { 30.11 + float value, range; 30.12 +}; 30.13 + 30.14 +struct psys_rnd3 { 30.15 + vec3_t value, range; 30.16 +}; 30.17 + 30.18 +struct psys_anm_rnd { 30.19 + struct psys_track value, range; 30.20 +}; 30.21 + 30.22 +struct psys_anm_rnd3 { 30.23 + struct psys_track3 value, range; 30.24 +}; 30.25 + 30.26 +#define PSYS_EVAL_CUR ANM_TIME_INVAL 30.27 + 30.28 +int psys_init_anm_rnd(struct psys_anm_rnd *v); 30.29 +void psys_destroy_anm_rnd(struct psys_anm_rnd *v); 30.30 +int psys_init_anm_rnd3(struct psys_anm_rnd3 *v); 30.31 +void psys_destroy_anm_rnd3(struct psys_anm_rnd3 *v); 30.32 + 30.33 +void psys_set_rnd(struct psys_rnd *r, float val, float range); 30.34 +void psys_set_rnd3(struct psys_rnd3 *r, vec3_t val, vec3_t range); 30.35 + 30.36 +void psys_set_anm_rnd(struct psys_anm_rnd *r, anm_time_t tm, float val, float range); 30.37 +void psys_set_anm_rnd3(struct psys_anm_rnd3 *r, anm_time_t tm, vec3_t val, vec3_t range); 30.38 + 30.39 +float psys_eval_rnd(struct psys_rnd *r); 30.40 +vec3_t psys_eval_rnd3(struct psys_rnd3 *r); 30.41 + 30.42 +float psys_eval_anm_rnd(struct psys_anm_rnd *r, anm_time_t tm); 30.43 +vec3_t psys_eval_anm_rnd3(struct psys_anm_rnd3 *r, anm_time_t tm); 30.44 + 30.45 + 30.46 +#endif /* RNDVAL_H_ */