dungeon_crawler

changeset 48:aa9e28670ae2

added sound playback, more to do
author John Tsiombikas <nuclear@member.fsf.org>
date Mon, 17 Sep 2012 08:40:59 +0300
parents d52711f2b9a1
children 303743485aba
files prototype/Makefile.in prototype/kdtree/kdtree.c prototype/kdtree/kdtree.h prototype/src/audio/audio.cc prototype/src/audio/audio.h prototype/src/audio/auman.cc prototype/src/audio/auman.h prototype/src/audio/sample.cc prototype/src/audio/sample.h prototype/src/audio/source.cc prototype/src/audio/source.h prototype/src/camera.cc prototype/src/camera.h prototype/src/dataset.h prototype/src/level.cc prototype/src/level.h prototype/src/main.cc prototype/src/material.cc prototype/src/material.h prototype/src/texman.cc prototype/src/texman.h prototype/src/texture.cc prototype/src/texture.h prototype/src/tile.cc prototype/src/tile.h prototype/src/tileset.cc prototype/src/tileset.h
diffstat 27 files changed, 1473 insertions(+), 117 deletions(-) [+]
line diff
     1.1 --- a/prototype/Makefile.in	Sun Sep 16 08:16:50 2012 +0300
     1.2 +++ b/prototype/Makefile.in	Mon Sep 17 08:40:59 2012 +0300
     1.3 @@ -1,6 +1,7 @@
     1.4  csrc = $(wildcard src/*.c) \
     1.5  	   $(wildcard vmath/*.c) \
     1.6 -	   $(wildcard drawtext/*.c)
     1.7 +	   $(wildcard drawtext/*.c) \
     1.8 +	   $(wildcard kdtree/*.c)
     1.9  
    1.10  ccsrc = $(wildcard src/*.cc) \
    1.11  		$(wildcard src/audio/*.cc) \
    1.12 @@ -12,7 +13,7 @@
    1.13  
    1.14  warn = -Wall -Wno-format-extra-args -Wno-char-subscripts
    1.15  
    1.16 -inc = -I. -Isrc/audio -Ivmath -Idrawtext `pkg-config --cflags freetype2`
    1.17 +inc = -I. -Isrc -Ivmath -Idrawtext -Ikdtree `pkg-config --cflags freetype2`
    1.18  
    1.19  CFLAGS = -pedantic $(warn) $(dbg) $(opt) $(inc)
    1.20  CXXFLAGS = $(CFLAGS) $(cxx11_cflags)
     2.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     2.2 +++ b/prototype/kdtree/kdtree.c	Mon Sep 17 08:40:59 2012 +0300
     2.3 @@ -0,0 +1,840 @@
     2.4 +/*
     2.5 +This file is part of ``kdtree'', a library for working with kd-trees.
     2.6 +Copyright (C) 2007-2011 John Tsiombikas <nuclear@member.fsf.org>
     2.7 +
     2.8 +Redistribution and use in source and binary forms, with or without
     2.9 +modification, are permitted provided that the following conditions are met:
    2.10 +
    2.11 +1. Redistributions of source code must retain the above copyright notice, this
    2.12 +   list of conditions and the following disclaimer.
    2.13 +2. Redistributions in binary form must reproduce the above copyright notice,
    2.14 +   this list of conditions and the following disclaimer in the documentation
    2.15 +   and/or other materials provided with the distribution.
    2.16 +3. The name of the author may not be used to endorse or promote products
    2.17 +   derived from this software without specific prior written permission.
    2.18 +
    2.19 +THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
    2.20 +WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
    2.21 +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
    2.22 +EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
    2.23 +EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
    2.24 +OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
    2.25 +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
    2.26 +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
    2.27 +IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
    2.28 +OF SUCH DAMAGE.
    2.29 +*/
    2.30 +/* single nearest neighbor search written by Tamas Nepusz <tamas@cs.rhul.ac.uk> */
    2.31 +#include <stdio.h>
    2.32 +#include <stdlib.h>
    2.33 +#include <string.h>
    2.34 +#include <math.h>
    2.35 +#include "kdtree.h"
    2.36 +
    2.37 +#define USE_LIST_NODE_ALLOCATOR
    2.38 +#define NO_PTHREADS
    2.39 +#define I_WANT_THREAD_BUGS
    2.40 +
    2.41 +#if defined(WIN32) || defined(__WIN32__)
    2.42 +#include <malloc.h>
    2.43 +#endif
    2.44 +
    2.45 +#ifdef USE_LIST_NODE_ALLOCATOR
    2.46 +
    2.47 +#ifndef NO_PTHREADS
    2.48 +#include <pthread.h>
    2.49 +#else
    2.50 +
    2.51 +#ifndef I_WANT_THREAD_BUGS
    2.52 +#error "You are compiling with the fast list node allocator, with pthreads disabled! This WILL break if used from multiple threads."
    2.53 +#endif	/* I want thread bugs */
    2.54 +
    2.55 +#endif	/* pthread support */
    2.56 +#endif	/* use list node allocator */
    2.57 +
    2.58 +struct kdhyperrect {
    2.59 +	int dim;
    2.60 +	double *min, *max;              /* minimum/maximum coords */
    2.61 +};
    2.62 +
    2.63 +struct kdnode {
    2.64 +	double *pos;
    2.65 +	int dir;
    2.66 +	void *data;
    2.67 +
    2.68 +	struct kdnode *left, *right;	/* negative/positive side */
    2.69 +};
    2.70 +
    2.71 +struct res_node {
    2.72 +	struct kdnode *item;
    2.73 +	double dist_sq;
    2.74 +	struct res_node *next;
    2.75 +};
    2.76 +
    2.77 +struct kdtree {
    2.78 +	int dim;
    2.79 +	struct kdnode *root;
    2.80 +	struct kdhyperrect *rect;
    2.81 +	void (*destr)(void*);
    2.82 +};
    2.83 +
    2.84 +struct kdres {
    2.85 +	struct kdtree *tree;
    2.86 +	struct res_node *rlist, *riter;
    2.87 +	int size;
    2.88 +};
    2.89 +
    2.90 +#define SQ(x)			((x) * (x))
    2.91 +
    2.92 +
    2.93 +static void clear_rec(struct kdnode *node, void (*destr)(void*));
    2.94 +static int insert_rec(struct kdnode **node, const double *pos, void *data, int dir, int dim);
    2.95 +static int rlist_insert(struct res_node *list, struct kdnode *item, double dist_sq);
    2.96 +static void clear_results(struct kdres *set);
    2.97 +
    2.98 +static struct kdhyperrect* hyperrect_create(int dim, const double *min, const double *max);
    2.99 +static void hyperrect_free(struct kdhyperrect *rect);
   2.100 +static struct kdhyperrect* hyperrect_duplicate(const struct kdhyperrect *rect);
   2.101 +static void hyperrect_extend(struct kdhyperrect *rect, const double *pos);
   2.102 +static double hyperrect_dist_sq(struct kdhyperrect *rect, const double *pos);
   2.103 +
   2.104 +#ifdef USE_LIST_NODE_ALLOCATOR
   2.105 +static struct res_node *alloc_resnode(void);
   2.106 +static void free_resnode(struct res_node*);
   2.107 +#else
   2.108 +#define alloc_resnode()		malloc(sizeof(struct res_node))
   2.109 +#define free_resnode(n)		free(n)
   2.110 +#endif
   2.111 +
   2.112 +
   2.113 +
   2.114 +struct kdtree *kd_create(int k)
   2.115 +{
   2.116 +	struct kdtree *tree;
   2.117 +
   2.118 +	if(!(tree = malloc(sizeof *tree))) {
   2.119 +		return 0;
   2.120 +	}
   2.121 +
   2.122 +	tree->dim = k;
   2.123 +	tree->root = 0;
   2.124 +	tree->destr = 0;
   2.125 +	tree->rect = 0;
   2.126 +
   2.127 +	return tree;
   2.128 +}
   2.129 +
   2.130 +void kd_free(struct kdtree *tree)
   2.131 +{
   2.132 +	if(tree) {
   2.133 +		kd_clear(tree);
   2.134 +		free(tree);
   2.135 +	}
   2.136 +}
   2.137 +
   2.138 +static void clear_rec(struct kdnode *node, void (*destr)(void*))
   2.139 +{
   2.140 +	if(!node) return;
   2.141 +
   2.142 +	clear_rec(node->left, destr);
   2.143 +	clear_rec(node->right, destr);
   2.144 +	
   2.145 +	if(destr) {
   2.146 +		destr(node->data);
   2.147 +	}
   2.148 +	free(node->pos);
   2.149 +	free(node);
   2.150 +}
   2.151 +
   2.152 +void kd_clear(struct kdtree *tree)
   2.153 +{
   2.154 +	clear_rec(tree->root, tree->destr);
   2.155 +	tree->root = 0;
   2.156 +
   2.157 +	if (tree->rect) {
   2.158 +		hyperrect_free(tree->rect);
   2.159 +		tree->rect = 0;
   2.160 +	}
   2.161 +}
   2.162 +
   2.163 +void kd_data_destructor(struct kdtree *tree, void (*destr)(void*))
   2.164 +{
   2.165 +	tree->destr = destr;
   2.166 +}
   2.167 +
   2.168 +
   2.169 +static int insert_rec(struct kdnode **nptr, const double *pos, void *data, int dir, int dim)
   2.170 +{
   2.171 +	int new_dir;
   2.172 +	struct kdnode *node;
   2.173 +
   2.174 +	if(!*nptr) {
   2.175 +		if(!(node = malloc(sizeof *node))) {
   2.176 +			return -1;
   2.177 +		}
   2.178 +		if(!(node->pos = malloc(dim * sizeof *node->pos))) {
   2.179 +			free(node);
   2.180 +			return -1;
   2.181 +		}
   2.182 +		memcpy(node->pos, pos, dim * sizeof *node->pos);
   2.183 +		node->data = data;
   2.184 +		node->dir = dir;
   2.185 +		node->left = node->right = 0;
   2.186 +		*nptr = node;
   2.187 +		return 0;
   2.188 +	}
   2.189 +
   2.190 +	node = *nptr;
   2.191 +	new_dir = (node->dir + 1) % dim;
   2.192 +	if(pos[node->dir] < node->pos[node->dir]) {
   2.193 +		return insert_rec(&(*nptr)->left, pos, data, new_dir, dim);
   2.194 +	}
   2.195 +	return insert_rec(&(*nptr)->right, pos, data, new_dir, dim);
   2.196 +}
   2.197 +
   2.198 +int kd_insert(struct kdtree *tree, const double *pos, void *data)
   2.199 +{
   2.200 +	if (insert_rec(&tree->root, pos, data, 0, tree->dim)) {
   2.201 +		return -1;
   2.202 +	}
   2.203 +
   2.204 +	if (tree->rect == 0) {
   2.205 +		tree->rect = hyperrect_create(tree->dim, pos, pos);
   2.206 +	} else {
   2.207 +		hyperrect_extend(tree->rect, pos);
   2.208 +	}
   2.209 +
   2.210 +	return 0;
   2.211 +}
   2.212 +
   2.213 +int kd_insertf(struct kdtree *tree, const float *pos, void *data)
   2.214 +{
   2.215 +	static double sbuf[16];
   2.216 +	double *bptr, *buf = 0;
   2.217 +	int res, dim = tree->dim;
   2.218 +
   2.219 +	if(dim > 16) {
   2.220 +#ifndef NO_ALLOCA
   2.221 +		if(dim <= 256)
   2.222 +			bptr = buf = alloca(dim * sizeof *bptr);
   2.223 +		else
   2.224 +#endif
   2.225 +			if(!(bptr = buf = malloc(dim * sizeof *bptr))) {
   2.226 +				return -1;
   2.227 +			}
   2.228 +	} else {
   2.229 +		bptr = buf = sbuf;
   2.230 +	}
   2.231 +
   2.232 +	while(dim-- > 0) {
   2.233 +		*bptr++ = *pos++;
   2.234 +	}
   2.235 +
   2.236 +	res = kd_insert(tree, buf, data);
   2.237 +#ifndef NO_ALLOCA
   2.238 +	if(tree->dim > 256)
   2.239 +#else
   2.240 +	if(tree->dim > 16)
   2.241 +#endif
   2.242 +		free(buf);
   2.243 +	return res;
   2.244 +}
   2.245 +
   2.246 +int kd_insert3(struct kdtree *tree, double x, double y, double z, void *data)
   2.247 +{
   2.248 +	double buf[3];
   2.249 +	buf[0] = x;
   2.250 +	buf[1] = y;
   2.251 +	buf[2] = z;
   2.252 +	return kd_insert(tree, buf, data);
   2.253 +}
   2.254 +
   2.255 +int kd_insert3f(struct kdtree *tree, float x, float y, float z, void *data)
   2.256 +{
   2.257 +	double buf[3];
   2.258 +	buf[0] = x;
   2.259 +	buf[1] = y;
   2.260 +	buf[2] = z;
   2.261 +	return kd_insert(tree, buf, data);
   2.262 +}
   2.263 +
   2.264 +static int find_nearest(struct kdnode *node, const double *pos, double range, struct res_node *list, int ordered, int dim)
   2.265 +{
   2.266 +	double dist_sq, dx;
   2.267 +	int i, ret, added_res = 0;
   2.268 +
   2.269 +	if(!node) return 0;
   2.270 +
   2.271 +	dist_sq = 0;
   2.272 +	for(i=0; i<dim; i++) {
   2.273 +		dist_sq += SQ(node->pos[i] - pos[i]);
   2.274 +	}
   2.275 +	if(dist_sq <= SQ(range)) {
   2.276 +		if(rlist_insert(list, node, ordered ? dist_sq : -1.0) == -1) {
   2.277 +			return -1;
   2.278 +		}
   2.279 +		added_res = 1;
   2.280 +	}
   2.281 +
   2.282 +	dx = pos[node->dir] - node->pos[node->dir];
   2.283 +
   2.284 +	ret = find_nearest(dx <= 0.0 ? node->left : node->right, pos, range, list, ordered, dim);
   2.285 +	if(ret >= 0 && fabs(dx) < range) {
   2.286 +		added_res += ret;
   2.287 +		ret = find_nearest(dx <= 0.0 ? node->right : node->left, pos, range, list, ordered, dim);
   2.288 +	}
   2.289 +	if(ret == -1) {
   2.290 +		return -1;
   2.291 +	}
   2.292 +	added_res += ret;
   2.293 +
   2.294 +	return added_res;
   2.295 +}
   2.296 +
   2.297 +#if 0
   2.298 +static int find_nearest_n(struct kdnode *node, const double *pos, double range, int num, struct rheap *heap, int dim)
   2.299 +{
   2.300 +	double dist_sq, dx;
   2.301 +	int i, ret, added_res = 0;
   2.302 +
   2.303 +	if(!node) return 0;
   2.304 +	
   2.305 +	/* if the photon is close enough, add it to the result heap */
   2.306 +	dist_sq = 0;
   2.307 +	for(i=0; i<dim; i++) {
   2.308 +		dist_sq += SQ(node->pos[i] - pos[i]);
   2.309 +	}
   2.310 +	if(dist_sq <= range_sq) {
   2.311 +		if(heap->size >= num) {
   2.312 +			/* get furthest element */
   2.313 +			struct res_node *maxelem = rheap_get_max(heap);
   2.314 +
   2.315 +			/* and check if the new one is closer than that */
   2.316 +			if(maxelem->dist_sq > dist_sq) {
   2.317 +				rheap_remove_max(heap);
   2.318 +
   2.319 +				if(rheap_insert(heap, node, dist_sq) == -1) {
   2.320 +					return -1;
   2.321 +				}
   2.322 +				added_res = 1;
   2.323 +
   2.324 +				range_sq = dist_sq;
   2.325 +			}
   2.326 +		} else {
   2.327 +			if(rheap_insert(heap, node, dist_sq) == -1) {
   2.328 +				return =1;
   2.329 +			}
   2.330 +			added_res = 1;
   2.331 +		}
   2.332 +	}
   2.333 +
   2.334 +
   2.335 +	/* find signed distance from the splitting plane */
   2.336 +	dx = pos[node->dir] - node->pos[node->dir];
   2.337 +
   2.338 +	ret = find_nearest_n(dx <= 0.0 ? node->left : node->right, pos, range, num, heap, dim);
   2.339 +	if(ret >= 0 && fabs(dx) < range) {
   2.340 +		added_res += ret;
   2.341 +		ret = find_nearest_n(dx <= 0.0 ? node->right : node->left, pos, range, num, heap, dim);
   2.342 +	}
   2.343 +
   2.344 +}
   2.345 +#endif
   2.346 +
   2.347 +static void kd_nearest_i(struct kdnode *node, const double *pos, struct kdnode **result, double *result_dist_sq, struct kdhyperrect* rect)
   2.348 +{
   2.349 +	int dir = node->dir;
   2.350 +	int i;
   2.351 +	double dummy, dist_sq;
   2.352 +	struct kdnode *nearer_subtree, *farther_subtree;
   2.353 +	double *nearer_hyperrect_coord, *farther_hyperrect_coord;
   2.354 +
   2.355 +	/* Decide whether to go left or right in the tree */
   2.356 +	dummy = pos[dir] - node->pos[dir];
   2.357 +	if (dummy <= 0) {
   2.358 +		nearer_subtree = node->left;
   2.359 +		farther_subtree = node->right;
   2.360 +		nearer_hyperrect_coord = rect->max + dir;
   2.361 +		farther_hyperrect_coord = rect->min + dir;
   2.362 +	} else {
   2.363 +		nearer_subtree = node->right;
   2.364 +		farther_subtree = node->left;
   2.365 +		nearer_hyperrect_coord = rect->min + dir;
   2.366 +		farther_hyperrect_coord = rect->max + dir;
   2.367 +	}
   2.368 +
   2.369 +	if (nearer_subtree) {
   2.370 +		/* Slice the hyperrect to get the hyperrect of the nearer subtree */
   2.371 +		dummy = *nearer_hyperrect_coord;
   2.372 +		*nearer_hyperrect_coord = node->pos[dir];
   2.373 +		/* Recurse down into nearer subtree */
   2.374 +		kd_nearest_i(nearer_subtree, pos, result, result_dist_sq, rect);
   2.375 +		/* Undo the slice */
   2.376 +		*nearer_hyperrect_coord = dummy;
   2.377 +	}
   2.378 +
   2.379 +	/* Check the distance of the point at the current node, compare it
   2.380 +	 * with our best so far */
   2.381 +	dist_sq = 0;
   2.382 +	for(i=0; i < rect->dim; i++) {
   2.383 +		dist_sq += SQ(node->pos[i] - pos[i]);
   2.384 +	}
   2.385 +	if (dist_sq < *result_dist_sq) {
   2.386 +		*result = node;
   2.387 +		*result_dist_sq = dist_sq;
   2.388 +	}
   2.389 +
   2.390 +	if (farther_subtree) {
   2.391 +		/* Get the hyperrect of the farther subtree */
   2.392 +		dummy = *farther_hyperrect_coord;
   2.393 +		*farther_hyperrect_coord = node->pos[dir];
   2.394 +		/* Check if we have to recurse down by calculating the closest
   2.395 +		 * point of the hyperrect and see if it's closer than our
   2.396 +		 * minimum distance in result_dist_sq. */
   2.397 +		if (hyperrect_dist_sq(rect, pos) < *result_dist_sq) {
   2.398 +			/* Recurse down into farther subtree */
   2.399 +			kd_nearest_i(farther_subtree, pos, result, result_dist_sq, rect);
   2.400 +		}
   2.401 +		/* Undo the slice on the hyperrect */
   2.402 +		*farther_hyperrect_coord = dummy;
   2.403 +	}
   2.404 +}
   2.405 +
   2.406 +struct kdres *kd_nearest(struct kdtree *kd, const double *pos)
   2.407 +{
   2.408 +	struct kdhyperrect *rect;
   2.409 +	struct kdnode *result;
   2.410 +	struct kdres *rset;
   2.411 +	double dist_sq;
   2.412 +	int i;
   2.413 +
   2.414 +	if (!kd) return 0;
   2.415 +	if (!kd->rect) return 0;
   2.416 +
   2.417 +	/* Allocate result set */
   2.418 +	if(!(rset = malloc(sizeof *rset))) {
   2.419 +		return 0;
   2.420 +	}
   2.421 +	if(!(rset->rlist = alloc_resnode())) {
   2.422 +		free(rset);
   2.423 +		return 0;
   2.424 +	}
   2.425 +	rset->rlist->next = 0;
   2.426 +	rset->tree = kd;
   2.427 +
   2.428 +	/* Duplicate the bounding hyperrectangle, we will work on the copy */
   2.429 +	if (!(rect = hyperrect_duplicate(kd->rect))) {
   2.430 +		kd_res_free(rset);
   2.431 +		return 0;
   2.432 +	}
   2.433 +
   2.434 +	/* Our first guesstimate is the root node */
   2.435 +	result = kd->root;
   2.436 +	dist_sq = 0;
   2.437 +	for (i = 0; i < kd->dim; i++)
   2.438 +		dist_sq += SQ(result->pos[i] - pos[i]);
   2.439 +
   2.440 +	/* Search for the nearest neighbour recursively */
   2.441 +	kd_nearest_i(kd->root, pos, &result, &dist_sq, rect);
   2.442 +
   2.443 +	/* Free the copy of the hyperrect */
   2.444 +	hyperrect_free(rect);
   2.445 +
   2.446 +	/* Store the result */
   2.447 +	if (result) {
   2.448 +		if (rlist_insert(rset->rlist, result, -1.0) == -1) {
   2.449 +			kd_res_free(rset);
   2.450 +			return 0;
   2.451 +		}
   2.452 +		rset->size = 1;
   2.453 +		kd_res_rewind(rset);
   2.454 +		return rset;
   2.455 +	} else {
   2.456 +		kd_res_free(rset);
   2.457 +		return 0;
   2.458 +	}
   2.459 +}
   2.460 +
   2.461 +struct kdres *kd_nearestf(struct kdtree *tree, const float *pos)
   2.462 +{
   2.463 +	static double sbuf[16];
   2.464 +	double *bptr, *buf = 0;
   2.465 +	int dim = tree->dim;
   2.466 +	struct kdres *res;
   2.467 +
   2.468 +	if(dim > 16) {
   2.469 +#ifndef NO_ALLOCA
   2.470 +		if(dim <= 256)
   2.471 +			bptr = buf = alloca(dim * sizeof *bptr);
   2.472 +		else
   2.473 +#endif
   2.474 +			if(!(bptr = buf = malloc(dim * sizeof *bptr))) {
   2.475 +				return 0;
   2.476 +			}
   2.477 +	} else {
   2.478 +		bptr = buf = sbuf;
   2.479 +	}
   2.480 +
   2.481 +	while(dim-- > 0) {
   2.482 +		*bptr++ = *pos++;
   2.483 +	}
   2.484 +
   2.485 +	res = kd_nearest(tree, buf);
   2.486 +#ifndef NO_ALLOCA
   2.487 +	if(tree->dim > 256)
   2.488 +#else
   2.489 +	if(tree->dim > 16)
   2.490 +#endif
   2.491 +		free(buf);
   2.492 +	return res;
   2.493 +}
   2.494 +
   2.495 +struct kdres *kd_nearest3(struct kdtree *tree, double x, double y, double z)
   2.496 +{
   2.497 +	double pos[3];
   2.498 +	pos[0] = x;
   2.499 +	pos[1] = y;
   2.500 +	pos[2] = z;
   2.501 +	return kd_nearest(tree, pos);
   2.502 +}
   2.503 +
   2.504 +struct kdres *kd_nearest3f(struct kdtree *tree, float x, float y, float z)
   2.505 +{
   2.506 +	double pos[3];
   2.507 +	pos[0] = x;
   2.508 +	pos[1] = y;
   2.509 +	pos[2] = z;
   2.510 +	return kd_nearest(tree, pos);
   2.511 +}
   2.512 +
   2.513 +/* ---- nearest N search ---- */
   2.514 +/*
   2.515 +static kdres *kd_nearest_n(struct kdtree *kd, const double *pos, int num)
   2.516 +{
   2.517 +	int ret;
   2.518 +	struct kdres *rset;
   2.519 +
   2.520 +	if(!(rset = malloc(sizeof *rset))) {
   2.521 +		return 0;
   2.522 +	}
   2.523 +	if(!(rset->rlist = alloc_resnode())) {
   2.524 +		free(rset);
   2.525 +		return 0;
   2.526 +	}
   2.527 +	rset->rlist->next = 0;
   2.528 +	rset->tree = kd;
   2.529 +
   2.530 +	if((ret = find_nearest_n(kd->root, pos, range, num, rset->rlist, kd->dim)) == -1) {
   2.531 +		kd_res_free(rset);
   2.532 +		return 0;
   2.533 +	}
   2.534 +	rset->size = ret;
   2.535 +	kd_res_rewind(rset);
   2.536 +	return rset;
   2.537 +}*/
   2.538 +
   2.539 +struct kdres *kd_nearest_range(struct kdtree *kd, const double *pos, double range)
   2.540 +{
   2.541 +	int ret;
   2.542 +	struct kdres *rset;
   2.543 +
   2.544 +	if(!(rset = malloc(sizeof *rset))) {
   2.545 +		return 0;
   2.546 +	}
   2.547 +	if(!(rset->rlist = alloc_resnode())) {
   2.548 +		free(rset);
   2.549 +		return 0;
   2.550 +	}
   2.551 +	rset->rlist->next = 0;
   2.552 +	rset->tree = kd;
   2.553 +
   2.554 +	if((ret = find_nearest(kd->root, pos, range, rset->rlist, 0, kd->dim)) == -1) {
   2.555 +		kd_res_free(rset);
   2.556 +		return 0;
   2.557 +	}
   2.558 +	rset->size = ret;
   2.559 +	kd_res_rewind(rset);
   2.560 +	return rset;
   2.561 +}
   2.562 +
   2.563 +struct kdres *kd_nearest_rangef(struct kdtree *kd, const float *pos, float range)
   2.564 +{
   2.565 +	static double sbuf[16];
   2.566 +	double *bptr, *buf = 0;
   2.567 +	int dim = kd->dim;
   2.568 +	struct kdres *res;
   2.569 +
   2.570 +	if(dim > 16) {
   2.571 +#ifndef NO_ALLOCA
   2.572 +		if(dim <= 256)
   2.573 +			bptr = buf = alloca(dim * sizeof *bptr);
   2.574 +		else
   2.575 +#endif
   2.576 +			if(!(bptr = buf = malloc(dim * sizeof *bptr))) {
   2.577 +				return 0;
   2.578 +			}
   2.579 +	} else {
   2.580 +		bptr = buf = sbuf;
   2.581 +	}
   2.582 +
   2.583 +	while(dim-- > 0) {
   2.584 +		*bptr++ = *pos++;
   2.585 +	}
   2.586 +
   2.587 +	res = kd_nearest_range(kd, buf, range);
   2.588 +#ifndef NO_ALLOCA
   2.589 +	if(kd->dim > 256)
   2.590 +#else
   2.591 +	if(kd->dim > 16)
   2.592 +#endif
   2.593 +		free(buf);
   2.594 +	return res;
   2.595 +}
   2.596 +
   2.597 +struct kdres *kd_nearest_range3(struct kdtree *tree, double x, double y, double z, double range)
   2.598 +{
   2.599 +	double buf[3];
   2.600 +	buf[0] = x;
   2.601 +	buf[1] = y;
   2.602 +	buf[2] = z;
   2.603 +	return kd_nearest_range(tree, buf, range);
   2.604 +}
   2.605 +
   2.606 +struct kdres *kd_nearest_range3f(struct kdtree *tree, float x, float y, float z, float range)
   2.607 +{
   2.608 +	double buf[3];
   2.609 +	buf[0] = x;
   2.610 +	buf[1] = y;
   2.611 +	buf[2] = z;
   2.612 +	return kd_nearest_range(tree, buf, range);
   2.613 +}
   2.614 +
   2.615 +void kd_res_free(struct kdres *rset)
   2.616 +{
   2.617 +	clear_results(rset);
   2.618 +	free_resnode(rset->rlist);
   2.619 +	free(rset);
   2.620 +}
   2.621 +
   2.622 +int kd_res_size(struct kdres *set)
   2.623 +{
   2.624 +	return (set->size);
   2.625 +}
   2.626 +
   2.627 +void kd_res_rewind(struct kdres *rset)
   2.628 +{
   2.629 +	rset->riter = rset->rlist->next;
   2.630 +}
   2.631 +
   2.632 +int kd_res_end(struct kdres *rset)
   2.633 +{
   2.634 +	return rset->riter == 0;
   2.635 +}
   2.636 +
   2.637 +int kd_res_next(struct kdres *rset)
   2.638 +{
   2.639 +	rset->riter = rset->riter->next;
   2.640 +	return rset->riter != 0;
   2.641 +}
   2.642 +
   2.643 +void *kd_res_item(struct kdres *rset, double *pos)
   2.644 +{
   2.645 +	if(rset->riter) {
   2.646 +		if(pos) {
   2.647 +			memcpy(pos, rset->riter->item->pos, rset->tree->dim * sizeof *pos);
   2.648 +		}
   2.649 +		return rset->riter->item->data;
   2.650 +	}
   2.651 +	return 0;
   2.652 +}
   2.653 +
   2.654 +void *kd_res_itemf(struct kdres *rset, float *pos)
   2.655 +{
   2.656 +	if(rset->riter) {
   2.657 +		if(pos) {
   2.658 +			int i;
   2.659 +			for(i=0; i<rset->tree->dim; i++) {
   2.660 +				pos[i] = rset->riter->item->pos[i];
   2.661 +			}
   2.662 +		}
   2.663 +		return rset->riter->item->data;
   2.664 +	}
   2.665 +	return 0;
   2.666 +}
   2.667 +
   2.668 +void *kd_res_item3(struct kdres *rset, double *x, double *y, double *z)
   2.669 +{
   2.670 +	if(rset->riter) {
   2.671 +		if(*x) *x = rset->riter->item->pos[0];
   2.672 +		if(*y) *y = rset->riter->item->pos[1];
   2.673 +		if(*z) *z = rset->riter->item->pos[2];
   2.674 +	}
   2.675 +	return 0;
   2.676 +}
   2.677 +
   2.678 +void *kd_res_item3f(struct kdres *rset, float *x, float *y, float *z)
   2.679 +{
   2.680 +	if(rset->riter) {
   2.681 +		if(*x) *x = rset->riter->item->pos[0];
   2.682 +		if(*y) *y = rset->riter->item->pos[1];
   2.683 +		if(*z) *z = rset->riter->item->pos[2];
   2.684 +	}
   2.685 +	return 0;
   2.686 +}
   2.687 +
   2.688 +void *kd_res_item_data(struct kdres *set)
   2.689 +{
   2.690 +	return kd_res_item(set, 0);
   2.691 +}
   2.692 +
   2.693 +/* ---- hyperrectangle helpers ---- */
   2.694 +static struct kdhyperrect* hyperrect_create(int dim, const double *min, const double *max)
   2.695 +{
   2.696 +	size_t size = dim * sizeof(double);
   2.697 +	struct kdhyperrect* rect = 0;
   2.698 +
   2.699 +	if (!(rect = malloc(sizeof(struct kdhyperrect)))) {
   2.700 +		return 0;
   2.701 +	}
   2.702 +
   2.703 +	rect->dim = dim;
   2.704 +	if (!(rect->min = malloc(size))) {
   2.705 +		free(rect);
   2.706 +		return 0;
   2.707 +	}
   2.708 +	if (!(rect->max = malloc(size))) {
   2.709 +		free(rect->min);
   2.710 +		free(rect);
   2.711 +		return 0;
   2.712 +	}
   2.713 +	memcpy(rect->min, min, size);
   2.714 +	memcpy(rect->max, max, size);
   2.715 +
   2.716 +	return rect;
   2.717 +}
   2.718 +
   2.719 +static void hyperrect_free(struct kdhyperrect *rect)
   2.720 +{
   2.721 +	free(rect->min);
   2.722 +	free(rect->max);
   2.723 +	free(rect);
   2.724 +}
   2.725 +
   2.726 +static struct kdhyperrect* hyperrect_duplicate(const struct kdhyperrect *rect)
   2.727 +{
   2.728 +	return hyperrect_create(rect->dim, rect->min, rect->max);
   2.729 +}
   2.730 +
   2.731 +static void hyperrect_extend(struct kdhyperrect *rect, const double *pos)
   2.732 +{
   2.733 +	int i;
   2.734 +
   2.735 +	for (i=0; i < rect->dim; i++) {
   2.736 +		if (pos[i] < rect->min[i]) {
   2.737 +			rect->min[i] = pos[i];
   2.738 +		}
   2.739 +		if (pos[i] > rect->max[i]) {
   2.740 +			rect->max[i] = pos[i];
   2.741 +		}
   2.742 +	}
   2.743 +}
   2.744 +
   2.745 +static double hyperrect_dist_sq(struct kdhyperrect *rect, const double *pos)
   2.746 +{
   2.747 +	int i;
   2.748 +	double result = 0;
   2.749 +
   2.750 +	for (i=0; i < rect->dim; i++) {
   2.751 +		if (pos[i] < rect->min[i]) {
   2.752 +			result += SQ(rect->min[i] - pos[i]);
   2.753 +		} else if (pos[i] > rect->max[i]) {
   2.754 +			result += SQ(rect->max[i] - pos[i]);
   2.755 +		}
   2.756 +	}
   2.757 +
   2.758 +	return result;
   2.759 +}
   2.760 +
   2.761 +/* ---- static helpers ---- */
   2.762 +
   2.763 +#ifdef USE_LIST_NODE_ALLOCATOR
   2.764 +/* special list node allocators. */
   2.765 +static struct res_node *free_nodes;
   2.766 +
   2.767 +#ifndef NO_PTHREADS
   2.768 +static pthread_mutex_t alloc_mutex = PTHREAD_MUTEX_INITIALIZER;
   2.769 +#endif
   2.770 +
   2.771 +static struct res_node *alloc_resnode(void)
   2.772 +{
   2.773 +	struct res_node *node;
   2.774 +
   2.775 +#ifndef NO_PTHREADS
   2.776 +	pthread_mutex_lock(&alloc_mutex);
   2.777 +#endif
   2.778 +
   2.779 +	if(!free_nodes) {
   2.780 +		node = malloc(sizeof *node);
   2.781 +	} else {
   2.782 +		node = free_nodes;
   2.783 +		free_nodes = free_nodes->next;
   2.784 +		node->next = 0;
   2.785 +	}
   2.786 +
   2.787 +#ifndef NO_PTHREADS
   2.788 +	pthread_mutex_unlock(&alloc_mutex);
   2.789 +#endif
   2.790 +
   2.791 +	return node;
   2.792 +}
   2.793 +
   2.794 +static void free_resnode(struct res_node *node)
   2.795 +{
   2.796 +#ifndef NO_PTHREADS
   2.797 +	pthread_mutex_lock(&alloc_mutex);
   2.798 +#endif
   2.799 +
   2.800 +	node->next = free_nodes;
   2.801 +	free_nodes = node;
   2.802 +
   2.803 +#ifndef NO_PTHREADS
   2.804 +	pthread_mutex_unlock(&alloc_mutex);
   2.805 +#endif
   2.806 +}
   2.807 +#endif	/* list node allocator or not */
   2.808 +
   2.809 +
   2.810 +/* inserts the item. if dist_sq is >= 0, then do an ordered insert */
   2.811 +/* TODO make the ordering code use heapsort */
   2.812 +static int rlist_insert(struct res_node *list, struct kdnode *item, double dist_sq)
   2.813 +{
   2.814 +	struct res_node *rnode;
   2.815 +
   2.816 +	if(!(rnode = alloc_resnode())) {
   2.817 +		return -1;
   2.818 +	}
   2.819 +	rnode->item = item;
   2.820 +	rnode->dist_sq = dist_sq;
   2.821 +
   2.822 +	if(dist_sq >= 0.0) {
   2.823 +		while(list->next && list->next->dist_sq < dist_sq) {
   2.824 +			list = list->next;
   2.825 +		}
   2.826 +	}
   2.827 +	rnode->next = list->next;
   2.828 +	list->next = rnode;
   2.829 +	return 0;
   2.830 +}
   2.831 +
   2.832 +static void clear_results(struct kdres *rset)
   2.833 +{
   2.834 +	struct res_node *tmp, *node = rset->rlist->next;
   2.835 +
   2.836 +	while(node) {
   2.837 +		tmp = node;
   2.838 +		node = node->next;
   2.839 +		free_resnode(tmp);
   2.840 +	}
   2.841 +
   2.842 +	rset->rlist->next = 0;
   2.843 +}
     3.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     3.2 +++ b/prototype/kdtree/kdtree.h	Mon Sep 17 08:40:59 2012 +0300
     3.3 @@ -0,0 +1,129 @@
     3.4 +/*
     3.5 +This file is part of ``kdtree'', a library for working with kd-trees.
     3.6 +Copyright (C) 2007-2011 John Tsiombikas <nuclear@member.fsf.org>
     3.7 +
     3.8 +Redistribution and use in source and binary forms, with or without
     3.9 +modification, are permitted provided that the following conditions are met:
    3.10 +
    3.11 +1. Redistributions of source code must retain the above copyright notice, this
    3.12 +   list of conditions and the following disclaimer.
    3.13 +2. Redistributions in binary form must reproduce the above copyright notice,
    3.14 +   this list of conditions and the following disclaimer in the documentation
    3.15 +   and/or other materials provided with the distribution.
    3.16 +3. The name of the author may not be used to endorse or promote products
    3.17 +   derived from this software without specific prior written permission.
    3.18 +
    3.19 +THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
    3.20 +WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
    3.21 +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
    3.22 +EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
    3.23 +EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
    3.24 +OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
    3.25 +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
    3.26 +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
    3.27 +IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
    3.28 +OF SUCH DAMAGE.
    3.29 +*/
    3.30 +#ifndef _KDTREE_H_
    3.31 +#define _KDTREE_H_
    3.32 +
    3.33 +#ifdef __cplusplus
    3.34 +extern "C" {
    3.35 +#endif
    3.36 +
    3.37 +struct kdtree;
    3.38 +struct kdres;
    3.39 +
    3.40 +
    3.41 +/* create a kd-tree for "k"-dimensional data */
    3.42 +struct kdtree *kd_create(int k);
    3.43 +
    3.44 +/* free the struct kdtree */
    3.45 +void kd_free(struct kdtree *tree);
    3.46 +
    3.47 +/* remove all the elements from the tree */
    3.48 +void kd_clear(struct kdtree *tree);
    3.49 +
    3.50 +/* if called with non-null 2nd argument, the function provided
    3.51 + * will be called on data pointers (see kd_insert) when nodes
    3.52 + * are to be removed from the tree.
    3.53 + */
    3.54 +void kd_data_destructor(struct kdtree *tree, void (*destr)(void*));
    3.55 +
    3.56 +/* insert a node, specifying its position, and optional data */
    3.57 +int kd_insert(struct kdtree *tree, const double *pos, void *data);
    3.58 +int kd_insertf(struct kdtree *tree, const float *pos, void *data);
    3.59 +int kd_insert3(struct kdtree *tree, double x, double y, double z, void *data);
    3.60 +int kd_insert3f(struct kdtree *tree, float x, float y, float z, void *data);
    3.61 +
    3.62 +/* Find the nearest node from a given point.
    3.63 + *
    3.64 + * This function returns a pointer to a result set with at most one element.
    3.65 + */
    3.66 +struct kdres *kd_nearest(struct kdtree *tree, const double *pos);
    3.67 +struct kdres *kd_nearestf(struct kdtree *tree, const float *pos);
    3.68 +struct kdres *kd_nearest3(struct kdtree *tree, double x, double y, double z);
    3.69 +struct kdres *kd_nearest3f(struct kdtree *tree, float x, float y, float z);
    3.70 +
    3.71 +/* Find the N nearest nodes from a given point.
    3.72 + *
    3.73 + * This function returns a pointer to a result set, with at most N elements,
    3.74 + * which can be manipulated with the kd_res_* functions.
    3.75 + * The returned pointer can be null as an indication of an error. Otherwise
    3.76 + * a valid result set is always returned which may contain 0 or more elements.
    3.77 + * The result set must be deallocated with kd_res_free after use.
    3.78 + */
    3.79 +/*
    3.80 +struct kdres *kd_nearest_n(struct kdtree *tree, const double *pos, int num);
    3.81 +struct kdres *kd_nearest_nf(struct kdtree *tree, const float *pos, int num);
    3.82 +struct kdres *kd_nearest_n3(struct kdtree *tree, double x, double y, double z);
    3.83 +struct kdres *kd_nearest_n3f(struct kdtree *tree, float x, float y, float z);
    3.84 +*/
    3.85 +
    3.86 +/* Find any nearest nodes from a given point within a range.
    3.87 + *
    3.88 + * This function returns a pointer to a result set, which can be manipulated
    3.89 + * by the kd_res_* functions.
    3.90 + * The returned pointer can be null as an indication of an error. Otherwise
    3.91 + * a valid result set is always returned which may contain 0 or more elements.
    3.92 + * The result set must be deallocated with kd_res_free after use.
    3.93 + */
    3.94 +struct kdres *kd_nearest_range(struct kdtree *tree, const double *pos, double range);
    3.95 +struct kdres *kd_nearest_rangef(struct kdtree *tree, const float *pos, float range);
    3.96 +struct kdres *kd_nearest_range3(struct kdtree *tree, double x, double y, double z, double range);
    3.97 +struct kdres *kd_nearest_range3f(struct kdtree *tree, float x, float y, float z, float range);
    3.98 +
    3.99 +/* frees a result set returned by kd_nearest_range() */
   3.100 +void kd_res_free(struct kdres *set);
   3.101 +
   3.102 +/* returns the size of the result set (in elements) */
   3.103 +int kd_res_size(struct kdres *set);
   3.104 +
   3.105 +/* rewinds the result set iterator */
   3.106 +void kd_res_rewind(struct kdres *set);
   3.107 +
   3.108 +/* returns non-zero if the set iterator reached the end after the last element */
   3.109 +int kd_res_end(struct kdres *set);
   3.110 +
   3.111 +/* advances the result set iterator, returns non-zero on success, zero if
   3.112 + * there are no more elements in the result set.
   3.113 + */
   3.114 +int kd_res_next(struct kdres *set);
   3.115 +
   3.116 +/* returns the data pointer (can be null) of the current result set item
   3.117 + * and optionally sets its position to the pointers(s) if not null.
   3.118 + */
   3.119 +void *kd_res_item(struct kdres *set, double *pos);
   3.120 +void *kd_res_itemf(struct kdres *set, float *pos);
   3.121 +void *kd_res_item3(struct kdres *set, double *x, double *y, double *z);
   3.122 +void *kd_res_item3f(struct kdres *set, float *x, float *y, float *z);
   3.123 +
   3.124 +/* equivalent to kd_res_item(set, 0) */
   3.125 +void *kd_res_item_data(struct kdres *set);
   3.126 +
   3.127 +
   3.128 +#ifdef __cplusplus
   3.129 +}
   3.130 +#endif
   3.131 +
   3.132 +#endif	/* _KDTREE_H_ */
     4.1 --- a/prototype/src/audio/audio.cc	Sun Sep 16 08:16:50 2012 +0300
     4.2 +++ b/prototype/src/audio/audio.cc	Mon Sep 17 08:40:59 2012 +0300
     4.3 @@ -2,15 +2,6 @@
     4.4  #include "openal.h"
     4.5  #include "audio.h"
     4.6  
     4.7 -#define CHECK_ERROR \
     4.8 -    do { \
     4.9 -        unsigned int err = alGetError(); \
    4.10 -        if(err != 0) { \
    4.11 -            fprintf(stderr, "%s:%d: AL error: %#x\n", __FILE__, __LINE__, err); \
    4.12 -            abort(); \
    4.13 -        } \
    4.14 -    } while(0)
    4.15 -
    4.16  static ALCdevice *dev;
    4.17  static ALCcontext *ctx;
    4.18  
     5.1 --- a/prototype/src/audio/audio.h	Sun Sep 16 08:16:50 2012 +0300
     5.2 +++ b/prototype/src/audio/audio.h	Mon Sep 17 08:40:59 2012 +0300
     5.3 @@ -4,5 +4,4 @@
     5.4  bool init_audio();
     5.5  void destroy_audio();
     5.6  
     5.7 -
     5.8  #endif	/* AUDIO_H_ */
     6.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     6.2 +++ b/prototype/src/audio/auman.cc	Mon Sep 17 08:40:59 2012 +0300
     6.3 @@ -0,0 +1,68 @@
     6.4 +#include <algorithm>
     6.5 +#include <new>
     6.6 +#include "auman.h"
     6.7 +
     6.8 +AudioManager::AudioManager()
     6.9 +{
    6.10 +	if(!(sources = kd_create(3))) {
    6.11 +		fprintf(stderr, "failed to create kd tree\n");
    6.12 +		throw std::bad_alloc();
    6.13 +	}
    6.14 +}
    6.15 +
    6.16 +AudioManager::~AudioManager()
    6.17 +{
    6.18 +	kd_free(sources);
    6.19 +}
    6.20 +
    6.21 +void AudioManager::clear()
    6.22 +{
    6.23 +	kd_clear(sources);
    6.24 +
    6.25 +	for(auto s : active_set) {
    6.26 +		s->stop();
    6.27 +	}
    6.28 +	active_set.clear();
    6.29 +}
    6.30 +
    6.31 +void AudioManager::add_source(AudioSource *s)
    6.32 +{
    6.33 +	Vector3 pos = s->get_position();
    6.34 +	if(kd_insert3f(sources, pos.x, pos.y, pos.z, s) == -1) {
    6.35 +		fprintf(stderr, "AudioManager: failed to add source!\n");
    6.36 +	}
    6.37 +}
    6.38 +
    6.39 +void AudioManager::active_range(const Vector3 &pos, float range)
    6.40 +{
    6.41 +	std::set<AudioSource*> newset;
    6.42 +
    6.43 +	// find all the sources in the given range and construct newset.
    6.44 +	struct kdres *results = kd_nearest_range3f(sources, pos.x, pos.y, pos.z, range);
    6.45 +	while(!kd_res_end(results)) {
    6.46 +		newset.insert((AudioSource*)kd_res_item_data(results));
    6.47 +		kd_res_next(results);
    6.48 +	}
    6.49 +	kd_res_free(results);
    6.50 +
    6.51 +	/* for each of the currently active sources, if they're not in the
    6.52 +	 * new set, stop the playback.
    6.53 +	 */
    6.54 +	for(auto s : active_set) {
    6.55 +		if(newset.find(s) == newset.end()) {
    6.56 +			s->stop();
    6.57 +		}
    6.58 +	}
    6.59 +
    6.60 +	/* for each of the new active sources not found in the currently active
    6.61 +	 * set, start the playback.
    6.62 +	 */
    6.63 +	for(auto s : newset) {
    6.64 +		if(active_set.find(s) == active_set.end()) {
    6.65 +			s->play();
    6.66 +		}
    6.67 +	}
    6.68 +
    6.69 +	// swap the current with the new, previous current will be destroyed at end of scope
    6.70 +	std::swap(active_set, newset);
    6.71 +}
     7.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     7.2 +++ b/prototype/src/audio/auman.h	Mon Sep 17 08:40:59 2012 +0300
     7.3 @@ -0,0 +1,23 @@
     7.4 +#ifndef AUMAN_H_
     7.5 +#define AUMAN_H_
     7.6 +
     7.7 +#include <set>
     7.8 +#include "kdtree.h"
     7.9 +#include "source.h"
    7.10 +
    7.11 +class AudioManager {
    7.12 +private:
    7.13 +	struct kdtree *sources;
    7.14 +	std::set<AudioSource*> active_set;
    7.15 +
    7.16 +public:
    7.17 +	AudioManager();
    7.18 +	~AudioManager();
    7.19 +
    7.20 +	void clear();
    7.21 +	void add_source(AudioSource *s);
    7.22 +
    7.23 +	void active_range(const Vector3 &pos, float range);
    7.24 +};
    7.25 +
    7.26 +#endif	// AUMAN_H_
     8.1 --- a/prototype/src/audio/sample.cc	Sun Sep 16 08:16:50 2012 +0300
     8.2 +++ b/prototype/src/audio/sample.cc	Mon Sep 17 08:40:59 2012 +0300
     8.3 @@ -5,6 +5,17 @@
     8.4  #include "openal.h"
     8.5  #include "sample.h"
     8.6  
     8.7 +
     8.8 +#define CHECK_ERROR \
     8.9 +    do { \
    8.10 +        unsigned int err = alGetError(); \
    8.11 +        if(err != 0) { \
    8.12 +            fprintf(stderr, "%s:%d: AL error: %#x\n", __FILE__, __LINE__, err); \
    8.13 +            abort(); \
    8.14 +        } \
    8.15 +    } while(0)
    8.16 +
    8.17 +
    8.18  AudioSample::AudioSample()
    8.19  {
    8.20  	albuffer = 0;
    8.21 @@ -36,7 +47,7 @@
    8.22  	printf("loading sample: %s: %ld samples/s, %s (%d chan)\n", fname, vinfo->rate,
    8.23  			vinfo->channels == 1 ? "mono" : "stereo", vinfo->channels);
    8.24  
    8.25 -	long num_samples = ov_pcm_total(&vf, -1);
    8.26 +	long num_samples = ov_pcm_total(&vf, -1) * vinfo->channels;
    8.27  	int16_t *samples = new int16_t[num_samples];
    8.28  
    8.29  	long bufsz = num_samples * sizeof *samples;
    8.30 @@ -62,6 +73,7 @@
    8.31  	}
    8.32  
    8.33  	alBufferData(bufobj, alfmt, samples, bufsz, vinfo->rate);
    8.34 +	CHECK_ERROR;
    8.35  	if(alGetError()) {
    8.36  		fprintf(stderr, "failed to load sample data into OpenAL buffer: %u\n", bufobj);
    8.37  		goto err;
    8.38 @@ -82,3 +94,19 @@
    8.39  	}
    8.40  	return false;
    8.41  }
    8.42 +
    8.43 +AudioSample *load_audio_sample(const char *fname)
    8.44 +{
    8.45 +	AudioSample *s = new AudioSample;
    8.46 +
    8.47 +	if(!s->load(fname)) {
    8.48 +		delete s;
    8.49 +		s = 0;
    8.50 +	}
    8.51 +	return s;
    8.52 +}
    8.53 +
    8.54 +void destroy_audio_sample(AudioSample *s)
    8.55 +{
    8.56 +	delete s;
    8.57 +}
     9.1 --- a/prototype/src/audio/sample.h	Sun Sep 16 08:16:50 2012 +0300
     9.2 +++ b/prototype/src/audio/sample.h	Mon Sep 17 08:40:59 2012 +0300
     9.3 @@ -1,6 +1,8 @@
     9.4  #ifndef SAMPLE_H_
     9.5  #define SAMPLE_H_
     9.6  
     9.7 +#include "dataset.h"
     9.8 +
     9.9  class AudioSample {
    9.10  private:
    9.11  	unsigned int albuffer;
    9.12 @@ -12,6 +14,13 @@
    9.13  	~AudioSample();
    9.14  
    9.15  	bool load(const char *fname);
    9.16 +
    9.17 +	friend class AudioSource;
    9.18  };
    9.19  
    9.20 +typedef DataSet<AudioSample*> SampleSet;
    9.21 +
    9.22 +AudioSample *load_audio_sample(const char *fname);
    9.23 +void destroy_audio_sample(AudioSample *s);
    9.24 +
    9.25  #endif	// SAMPLE_H_
    10.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    10.2 +++ b/prototype/src/audio/source.cc	Mon Sep 17 08:40:59 2012 +0300
    10.3 @@ -0,0 +1,73 @@
    10.4 +#include "openal.h"
    10.5 +#include "source.h"
    10.6 +
    10.7 +AudioSource::AudioSource()
    10.8 +{
    10.9 +	sample = 0;
   10.10 +
   10.11 +	alGenSources(1, &alsrc);
   10.12 +	alSourcei(alsrc, AL_LOOPING, AL_TRUE);
   10.13 +}
   10.14 +
   10.15 +AudioSource::~AudioSource()
   10.16 +{
   10.17 +	if(alsrc) {
   10.18 +		if(is_playing()) {
   10.19 +			stop();
   10.20 +		}
   10.21 +		alDeleteSources(1, &alsrc);
   10.22 +	}
   10.23 +}
   10.24 +
   10.25 +void AudioSource::set_sample(const AudioSample *sample)
   10.26 +{
   10.27 +	stop();
   10.28 +
   10.29 +	if(sample) {
   10.30 +		if(!sample->albuffer) {
   10.31 +			fprintf(stderr, "%s: trying to attach null buffer!\n", __FUNCTION__);
   10.32 +			return;
   10.33 +		}
   10.34 +		alSourcei(alsrc, AL_BUFFER, sample->albuffer);
   10.35 +	}
   10.36 +	this->sample = sample;
   10.37 +}
   10.38 +
   10.39 +const AudioSample *AudioSource::get_sample() const
   10.40 +{
   10.41 +	return sample;
   10.42 +}
   10.43 +
   10.44 +void AudioSource::set_position(const Vector3 &pos, bool viewspace)
   10.45 +{
   10.46 +	alSourcei(alsrc, AL_SOURCE_RELATIVE, viewspace ? AL_TRUE : AL_FALSE);
   10.47 +	alSource3f(alsrc, AL_POSITION, pos.x, pos.y, pos.z);
   10.48 +}
   10.49 +
   10.50 +Vector3 AudioSource::get_position() const
   10.51 +{
   10.52 +	float pos[3];
   10.53 +	alGetSourcefv(alsrc, AL_POSITION, pos);
   10.54 +	return Vector3(pos[0], pos[1], pos[2]);
   10.55 +}
   10.56 +
   10.57 +bool AudioSource::is_playing() const
   10.58 +{
   10.59 +	int state;
   10.60 +	alGetSourcei(alsrc, AL_SOURCE_STATE, &state);
   10.61 +	return state == AL_PLAYING;
   10.62 +}
   10.63 +
   10.64 +void AudioSource::play()
   10.65 +{
   10.66 +	if(sample) {
   10.67 +		alSourcePlay(alsrc);
   10.68 +	}
   10.69 +}
   10.70 +
   10.71 +void AudioSource::stop()
   10.72 +{
   10.73 +	if(sample) {
   10.74 +		alSourceStop(alsrc);
   10.75 +	}
   10.76 +}
    11.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    11.2 +++ b/prototype/src/audio/source.h	Mon Sep 17 08:40:59 2012 +0300
    11.3 @@ -0,0 +1,27 @@
    11.4 +#ifndef SOURCE_H_
    11.5 +#define SOURCE_H_
    11.6 +
    11.7 +#include "vmath/vmath.h"
    11.8 +#include "sample.h"
    11.9 +
   11.10 +class AudioSource {
   11.11 +private:
   11.12 +	unsigned int alsrc;
   11.13 +	const AudioSample *sample;
   11.14 +
   11.15 +public:
   11.16 +	AudioSource();
   11.17 +	~AudioSource();
   11.18 +
   11.19 +	void set_sample(const AudioSample *sample);
   11.20 +	const AudioSample *get_sample() const;
   11.21 +
   11.22 +	void set_position(const Vector3 &pos, bool viewspace = false);
   11.23 +	Vector3 get_position() const;
   11.24 +
   11.25 +	bool is_playing() const;
   11.26 +	void play();
   11.27 +	void stop();
   11.28 +};
   11.29 +
   11.30 +#endif	// SOURCE_H_
    12.1 --- a/prototype/src/camera.cc	Sun Sep 16 08:16:50 2012 +0300
    12.2 +++ b/prototype/src/camera.cc	Mon Sep 17 08:40:59 2012 +0300
    12.3 @@ -132,6 +132,10 @@
    12.4  	inval_cache();
    12.5  }
    12.6  
    12.7 +const Vector3 &FpsCamera::get_position() const
    12.8 +{
    12.9 +	return pos;
   12.10 +}
   12.11  
   12.12  
   12.13  FlyCamera::FlyCamera()
    13.1 --- a/prototype/src/camera.h	Sun Sep 16 08:16:50 2012 +0300
    13.2 +++ b/prototype/src/camera.h	Mon Sep 17 08:40:59 2012 +0300
    13.3 @@ -56,6 +56,8 @@
    13.4  
    13.5  public:
    13.6  	void input_move(float x, float y, float z);
    13.7 +
    13.8 +	const Vector3 &get_position() const;
    13.9  };
   13.10  
   13.11  class FlyCamera : public Camera {
    14.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    14.2 +++ b/prototype/src/dataset.h	Mon Sep 17 08:40:59 2012 +0300
    14.3 @@ -0,0 +1,68 @@
    14.4 +#ifndef DATASET_H_
    14.5 +#define DATASET_H_
    14.6 +
    14.7 +#include <string.h>
    14.8 +#include <string>
    14.9 +#include <map>
   14.10 +#include <functional>
   14.11 +#include "datapath.h"
   14.12 +
   14.13 +template <typename T>
   14.14 +class DataSet {
   14.15 +private:
   14.16 +	mutable std::map<std::string, T> data;
   14.17 +
   14.18 +	std::function<T(const char*)> load;
   14.19 +	std::function<void(T)> destroy;
   14.20 +
   14.21 +public:
   14.22 +	DataSet(std::function<T(const char*)> load_func, std::function<void(T)> destr_func);
   14.23 +	~DataSet();
   14.24 +
   14.25 +	T get(const char *name) const;
   14.26 +};
   14.27 +
   14.28 +template <typename T>
   14.29 +DataSet<T>::DataSet(std::function<T(const char*)> load_func, std::function<void(T)> destr_func)
   14.30 +{
   14.31 +	load = load_func;
   14.32 +	destroy = destr_func;
   14.33 +}
   14.34 +
   14.35 +template <typename T>
   14.36 +DataSet<T>::~DataSet()
   14.37 +{
   14.38 +	if(destroy) {
   14.39 +		for(auto it : data) {
   14.40 +			destroy(it.second);
   14.41 +		}
   14.42 +	}
   14.43 +}
   14.44 +
   14.45 +template <typename T>
   14.46 +T DataSet<T>::get(const char *name) const
   14.47 +{
   14.48 +	auto iter = data.find(name);
   14.49 +	if(iter != data.end()) {
   14.50 +		return iter->second;
   14.51 +	}
   14.52 +
   14.53 +	const char *path, *slash;
   14.54 +	if((slash = strrchr(name, '/'))) {
   14.55 +		path = slash + 1;
   14.56 +	} else {
   14.57 +		path = name;
   14.58 +	}
   14.59 +	if(!(path = datafile_path(path))) {
   14.60 +		fprintf(stderr, "can't find data file: %s\n", name);
   14.61 +		return 0;
   14.62 +	}
   14.63 +
   14.64 +	T res = load(path);
   14.65 +	if(res) {
   14.66 +		data[name] = res;
   14.67 +	}
   14.68 +	return res;
   14.69 +}
   14.70 +
   14.71 +#endif	// DATASET_H_
    15.1 --- a/prototype/src/level.cc	Sun Sep 16 08:16:50 2012 +0300
    15.2 +++ b/prototype/src/level.cc	Mon Sep 17 08:40:59 2012 +0300
    15.3 @@ -107,6 +107,14 @@
    15.4  	return Vector3(posx, 0, posy);
    15.5  }
    15.6  
    15.7 +void Level::get_cell_coords_at(const Vector3 &pos, int *xptr, int *yptr) const
    15.8 +{
    15.9 +	float posx = pos.x + cell_size * (float)xsz / 2.0f;
   15.10 +	float posy = pos.z + cell_size * (float)ysz / 2.0f;
   15.11 +	*xptr = (int)round(posx / cell_size);
   15.12 +	*yptr = (int)round(posy / cell_size);
   15.13 +}
   15.14 +
   15.15  unsigned int Level::get_cell_dirmask(int x, int y) const
   15.16  {
   15.17  	unsigned int dmask = TILE_ALL;
   15.18 @@ -229,6 +237,16 @@
   15.19  }
   15.20  
   15.21  
   15.22 +AudioSample *Level::get_sample(int x, int y, int which) const
   15.23 +{
   15.24 +	const GridCell *cell = get_cell(x, y);
   15.25 +	if(!cell) {
   15.26 +		return 0;
   15.27 +	}
   15.28 +	return cell->get_sample(which);
   15.29 +}
   15.30 +
   15.31 +
   15.32  GridCell::GridCell(Tile *tile)
   15.33  {
   15.34  	if(tile) {
   15.35 @@ -285,3 +303,14 @@
   15.36  		psys_draw(ps);
   15.37  	}
   15.38  }
   15.39 +
   15.40 +AudioSample *GridCell::get_sample(int which) const
   15.41 +{
   15.42 +	for(auto tile : tiles) {
   15.43 +		AudioSample *s = tile->get_sample(which);
   15.44 +		if(s) {
   15.45 +			return s;
   15.46 +		}
   15.47 +	}
   15.48 +	return 0;
   15.49 +}
    16.1 --- a/prototype/src/level.h	Sun Sep 16 08:16:50 2012 +0300
    16.2 +++ b/prototype/src/level.h	Mon Sep 17 08:40:59 2012 +0300
    16.3 @@ -4,9 +4,9 @@
    16.4  #include <vector>
    16.5  #include "vmath/vmath.h"
    16.6  #include "psys/psys.h"
    16.7 +#include "tile.h"
    16.8  
    16.9  class GridCell;
   16.10 -class Tile;
   16.11  
   16.12  class Level {
   16.13  private:
   16.14 @@ -30,6 +30,7 @@
   16.15  
   16.16  	const GridCell *get_cell(int x, int y) const;
   16.17  	Vector3 get_cell_pos(int x, int y) const;
   16.18 +	void get_cell_coords_at(const Vector3 &pos, int *xptr, int *yptr) const;
   16.19  	unsigned int get_cell_dirmask(int x, int y) const;
   16.20  
   16.21  	void update(unsigned long msec, float dt);
   16.22 @@ -37,6 +38,8 @@
   16.23  	void draw() const;
   16.24  	void draw_lights() const;
   16.25  	void draw_post() const;
   16.26 +
   16.27 +	AudioSample *get_sample(int x, int y, int which) const;
   16.28  };
   16.29  
   16.30  class GridCell {
   16.31 @@ -57,6 +60,8 @@
   16.32  	void draw(unsigned int draw_mask) const;
   16.33  	void draw_lights(unsigned int draw_mask) const;
   16.34  	void draw_post(unsigned int draw_mask) const;
   16.35 +
   16.36 +	AudioSample *get_sample(int which) const;
   16.37  };
   16.38  
   16.39  #endif	// LEVEL_H_
    17.1 --- a/prototype/src/main.cc	Sun Sep 16 08:16:50 2012 +0300
    17.2 +++ b/prototype/src/main.cc	Mon Sep 17 08:40:59 2012 +0300
    17.3 @@ -5,7 +5,7 @@
    17.4  #include "opengl.h"
    17.5  #include "psys/psys.h"
    17.6  #include "level.h"
    17.7 -#include "texman.h"
    17.8 +#include "texture.h"
    17.9  #include "camera.h"
   17.10  #include "datapath.h"
   17.11  #include "tileset.h"
   17.12 @@ -14,7 +14,8 @@
   17.13  #include "cmdcon.h"
   17.14  #include "cfg.h"
   17.15  #include "timer.h"
   17.16 -#include "audio.h"
   17.17 +#include "audio/audio.h"
   17.18 +#include "audio/source.h"
   17.19  
   17.20  bool init(int xsz, int ysz);
   17.21  void cleanup();
   17.22 @@ -43,6 +44,8 @@
   17.23  
   17.24  static bool show_con;
   17.25  
   17.26 +static AudioSource *move_sound;
   17.27 +
   17.28  int main(int argc, char **argv)
   17.29  {
   17.30  	glutInit(&argc, argv);
   17.31 @@ -91,8 +94,17 @@
   17.32  
   17.33  	add_data_path(".");
   17.34  	add_data_path("data");
   17.35 +	add_data_path("data/audio");
   17.36  	add_data_path("sdr");
   17.37  
   17.38 +	if(cfg.sound && !init_audio()) {
   17.39 +		fprintf(stderr, "failed to initialize audio, continuing silently\n");
   17.40 +		cfg.sound = false;
   17.41 +	}
   17.42 +	if(cfg.sound) {
   17.43 +		move_sound = new AudioSource;
   17.44 +	}
   17.45 +
   17.46  	rend = new DeferredRenderer();
   17.47  	if(!cfg.use_deferred || !rend->init(xsz, ysz)) {
   17.48  		printf("falling back to crappy renderer...\n");
   17.49 @@ -126,17 +138,13 @@
   17.50  
   17.51  	cam.input_move(0, 0.5, 0);
   17.52  
   17.53 -	if(cfg.sound && !init_audio()) {
   17.54 -		fprintf(stderr, "failed to initialize audio, continuing silently\n");
   17.55 -		cfg.sound = false;
   17.56 -	}
   17.57 -
   17.58  	return true;
   17.59  }
   17.60  
   17.61  void cleanup()
   17.62  {
   17.63  	if(cfg.sound) {
   17.64 +		delete move_sound;
   17.65  		destroy_audio();
   17.66  	}
   17.67  
   17.68 @@ -238,17 +246,22 @@
   17.69  	float dx = 0, dy = 0;
   17.70  
   17.71  	// handle key input
   17.72 +	bool did_move = false;
   17.73  	if(keystate['w'] || keystate['W']) {
   17.74  		dy -= offs;
   17.75 +		did_move = true;
   17.76  	}
   17.77  	if(keystate['s'] || keystate['S']) {
   17.78  		dy += offs;
   17.79 +		did_move = true;
   17.80  	}
   17.81  	if(keystate['d'] || keystate['D']) {
   17.82  		dx += offs;
   17.83 +		did_move = true;
   17.84  	}
   17.85  	if(keystate['a'] || keystate['A']) {
   17.86  		dx -= offs;
   17.87 +		did_move = true;
   17.88  	}
   17.89  
   17.90  	cam.input_move(dx, 0, dy);
   17.91 @@ -256,6 +269,24 @@
   17.92  	tileset->update_tiles(msec);
   17.93  	level->update(msec, dt);
   17.94  
   17.95 +	// play the walking sound if we're walking
   17.96 +	int cellx, celly;
   17.97 +	level->get_cell_coords_at(cam.get_position(), &cellx, &celly);
   17.98 +
   17.99 +	const AudioSample *move_sample;
  17.100 +	if(did_move && (move_sample = level->get_sample(cellx, celly, TILE_SAMPLE_WALK))) {
  17.101 +		if(move_sample != move_sound->get_sample()) {
  17.102 +			move_sound->stop();
  17.103 +			move_sound->set_sample(move_sample);
  17.104 +			move_sound->play();
  17.105 +		}
  17.106 +	} else {
  17.107 +		if(move_sound->get_sample()) {
  17.108 +			move_sound->stop();
  17.109 +			move_sound->set_sample(0);
  17.110 +		}
  17.111 +	}
  17.112 +
  17.113  	last_upd = msec;
  17.114  }
  17.115  
  17.116 @@ -287,6 +318,27 @@
  17.117  		stereo_shift_pressed = true;
  17.118  		break;
  17.119  
  17.120 +	case 'p':
  17.121 +		{
  17.122 +			Vector3 pos = cam.get_position();
  17.123 +			int cell_x, cell_y;
  17.124 +			level->get_cell_coords_at(pos, &cell_x, &cell_y);
  17.125 +			printf("Current position: [%.2f %.2f %.2f]  cell: [%d %d]\n", pos.x, pos.y, pos.z,
  17.126 +					cell_x, cell_y);
  17.127 +		}
  17.128 +		break;
  17.129 +
  17.130 +	case 'P':
  17.131 +		{
  17.132 +			Vector3 pos = cam.get_position();
  17.133 +			int cell_x, cell_y;
  17.134 +			level->get_cell_coords_at(pos, &cell_x, &cell_y);
  17.135 +			AudioSample *sample = level->get_sample(cell_x, cell_y, TILE_SAMPLE_WALK);
  17.136 +			printf("walk sample: %p\n", (void*)sample);
  17.137 +		}
  17.138 +		break;
  17.139 +
  17.140 +
  17.141  	case '\n':
  17.142  	case '\r':
  17.143  		{
  17.144 @@ -375,5 +427,5 @@
  17.145  unsigned int load_psys_tex(const char *fname, void *cls)
  17.146  {
  17.147  	TextureSet *texset = tileset->get_textures();
  17.148 -	return texset->get_texture(fname);
  17.149 +	return texset->get(fname);
  17.150  }
    18.1 --- a/prototype/src/material.cc	Sun Sep 16 08:16:50 2012 +0300
    18.2 +++ b/prototype/src/material.cc	Mon Sep 17 08:40:59 2012 +0300
    18.3 @@ -48,7 +48,7 @@
    18.4  		for(int j=0; j<2; j++) {
    18.5  			aiString tex_name;
    18.6  			if(asstypes[i][j] > 0 && aiGetMaterialString(assmat, AI_MATKEY_TEXTURE(asstypes[i][j], 0), &tex_name) == 0) {
    18.7 -				tex[i] = texset->get_texture(tex_name.data);
    18.8 +				tex[i] = texset->get(tex_name.data);
    18.9  				break;
   18.10  			} else {
   18.11  				tex[i] = 0;
    19.1 --- a/prototype/src/material.h	Sun Sep 16 08:16:50 2012 +0300
    19.2 +++ b/prototype/src/material.h	Mon Sep 17 08:40:59 2012 +0300
    19.3 @@ -2,7 +2,7 @@
    19.4  #define MATERIAL_H_
    19.5  
    19.6  #include "color.h"
    19.7 -#include "texman.h"
    19.8 +#include "texture.h"
    19.9  
   19.10  enum {
   19.11  	TEXTYPE_DIFFUSE,
    20.1 --- a/prototype/src/texman.cc	Sun Sep 16 08:16:50 2012 +0300
    20.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
    20.3 @@ -1,75 +0,0 @@
    20.4 -#include <string.h>
    20.5 -#include "opengl.h"
    20.6 -#include "imago2.h"
    20.7 -#include "texman.h"
    20.8 -#include "datapath.h"
    20.9 -
   20.10 -unsigned int load_texture(const char *fname);
   20.11 -
   20.12 -TextureSet::~TextureSet()
   20.13 -{
   20.14 -	for(auto iter : textures) {
   20.15 -		glDeleteTextures(1, &iter.second);
   20.16 -	}
   20.17 -}
   20.18 -
   20.19 -unsigned int TextureSet::get_texture(const char *fname) const
   20.20 -{
   20.21 -	auto iter = textures.find(fname);
   20.22 -	if(iter != textures.end()) {
   20.23 -		return iter->second;
   20.24 -	}
   20.25 -
   20.26 -	const char *path, *slash;
   20.27 -	if((slash = strrchr(fname, '/'))) {
   20.28 -		path = slash + 1;
   20.29 -	} else {
   20.30 -		path = fname;
   20.31 -	}
   20.32 -	if(!(path = datafile_path(path))) {
   20.33 -		fprintf(stderr, "can't find texture: %s\n", fname);
   20.34 -		return 0;
   20.35 -	}
   20.36 -
   20.37 -	printf("loading texture: %s\n", path);
   20.38 -	unsigned int tex = load_texture(path);
   20.39 -	if(tex) {
   20.40 -		textures[fname] = tex;
   20.41 -	} else {
   20.42 -		fprintf(stderr, "failed to load texture: %s\n", path);
   20.43 -	}
   20.44 -	return tex;
   20.45 -}
   20.46 -
   20.47 -unsigned int load_texture(const char *fname)
   20.48 -{
   20.49 -	struct img_pixmap img;
   20.50 -
   20.51 -	img_init(&img);
   20.52 -	if(img_load(&img, fname) == -1) {
   20.53 -		img_destroy(&img);
   20.54 -		return 0;
   20.55 -	}
   20.56 -
   20.57 -	unsigned int intfmt = img_glintfmt(&img);
   20.58 -	unsigned int fmt = img_glfmt(&img);
   20.59 -	unsigned int type = img_gltype(&img);
   20.60 -
   20.61 -	unsigned int tex;
   20.62 -	glGenTextures(1, &tex);
   20.63 -	glBindTexture(GL_TEXTURE_2D, tex);
   20.64 -	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
   20.65 -	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
   20.66 -	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
   20.67 -	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
   20.68 -
   20.69 -	if(GLEW_SGIS_generate_mipmap) {
   20.70 -		glTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP_SGIS, GL_TRUE);
   20.71 -		glTexImage2D(GL_TEXTURE_2D, 0, intfmt, img.width, img.height, 0, fmt, type, img.pixels);
   20.72 -	} else {
   20.73 -		gluBuild2DMipmaps(GL_TEXTURE_2D, intfmt, img.width, img.height, fmt, type, img.pixels);
   20.74 -	}
   20.75 -
   20.76 -	img_destroy(&img);
   20.77 -	return tex;
   20.78 -}
    21.1 --- a/prototype/src/texman.h	Sun Sep 16 08:16:50 2012 +0300
    21.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
    21.3 @@ -1,17 +0,0 @@
    21.4 -#ifndef TEXMAN_H_
    21.5 -#define TEXMAN_H_
    21.6 -
    21.7 -#include <string>
    21.8 -#include <map>
    21.9 -
   21.10 -class TextureSet {
   21.11 -private:
   21.12 -	mutable std::map<std::string, unsigned int> textures;
   21.13 -
   21.14 -public:
   21.15 -	~TextureSet();
   21.16 -
   21.17 -	unsigned int get_texture(const char *fname) const;
   21.18 -};
   21.19 -
   21.20 -#endif	// TEXMAN_H_
    22.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    22.2 +++ b/prototype/src/texture.cc	Mon Sep 17 08:40:59 2012 +0300
    22.3 @@ -0,0 +1,41 @@
    22.4 +#include "opengl.h"
    22.5 +#include "imago2.h"
    22.6 +#include "texture.h"
    22.7 +
    22.8 +unsigned int load_texture(const char *fname)
    22.9 +{
   22.10 +	struct img_pixmap img;
   22.11 +
   22.12 +	img_init(&img);
   22.13 +	if(img_load(&img, fname) == -1) {
   22.14 +		img_destroy(&img);
   22.15 +		return 0;
   22.16 +	}
   22.17 +
   22.18 +	unsigned int intfmt = img_glintfmt(&img);
   22.19 +	unsigned int fmt = img_glfmt(&img);
   22.20 +	unsigned int type = img_gltype(&img);
   22.21 +
   22.22 +	unsigned int tex;
   22.23 +	glGenTextures(1, &tex);
   22.24 +	glBindTexture(GL_TEXTURE_2D, tex);
   22.25 +	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
   22.26 +	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
   22.27 +	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
   22.28 +	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
   22.29 +
   22.30 +	if(GLEW_SGIS_generate_mipmap) {
   22.31 +		glTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP_SGIS, GL_TRUE);
   22.32 +		glTexImage2D(GL_TEXTURE_2D, 0, intfmt, img.width, img.height, 0, fmt, type, img.pixels);
   22.33 +	} else {
   22.34 +		gluBuild2DMipmaps(GL_TEXTURE_2D, intfmt, img.width, img.height, fmt, type, img.pixels);
   22.35 +	}
   22.36 +
   22.37 +	img_destroy(&img);
   22.38 +	return tex;
   22.39 +}
   22.40 +
   22.41 +void destroy_texture(unsigned int tex)
   22.42 +{
   22.43 +	glDeleteTextures(1, &tex);
   22.44 +}
    23.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    23.2 +++ b/prototype/src/texture.h	Mon Sep 17 08:40:59 2012 +0300
    23.3 @@ -0,0 +1,11 @@
    23.4 +#ifndef TEXTURE_H_
    23.5 +#define TEXTURE_H_
    23.6 +
    23.7 +#include "dataset.h"
    23.8 +
    23.9 +typedef DataSet<unsigned int> TextureSet;
   23.10 +
   23.11 +unsigned int load_texture(const char *fname);
   23.12 +void destroy_texture(unsigned int tex);
   23.13 +
   23.14 +#endif	// TEXTURE_H_
    24.1 --- a/prototype/src/tile.cc	Sun Sep 16 08:16:50 2012 +0300
    24.2 +++ b/prototype/src/tile.cc	Mon Sep 17 08:40:59 2012 +0300
    24.3 @@ -21,6 +21,8 @@
    24.4  {
    24.5  	tset = tileset;
    24.6  	last_upd = LONG_MIN;
    24.7 +
    24.8 +	memset(samples, 0, sizeof samples);
    24.9  }
   24.10  
   24.11  Tile::~Tile()
   24.12 @@ -39,6 +41,14 @@
   24.13  	}
   24.14  }
   24.15  
   24.16 +AudioSample *Tile::get_sample(int sidx) const
   24.17 +{
   24.18 +	if(sidx >= 0 && sidx < MAX_TILE_SAMPLES) {
   24.19 +		return samples[sidx];
   24.20 +	}
   24.21 +	return 0;
   24.22 +}
   24.23 +
   24.24  const struct psys_attributes * const *Tile::get_unique_psys() const
   24.25  {
   24.26  	return &psattr[0];
   24.27 @@ -85,6 +95,11 @@
   24.28  	printf("loaded tile %s: %d meshes, %d lights\n", saved_fname, (int)meshes.size(), (int)lights.size());
   24.29  
   24.30  	aiReleaseImport(scn);
   24.31 +
   24.32 +	// XXX get the default audio samples for now
   24.33 +	SampleSet *sampleset = tset->get_samples();
   24.34 +	samples[TILE_SAMPLE_WALK] = sampleset->get("walk_stone.ogg");
   24.35 +	samples[TILE_SAMPLE_RUN] = sampleset->get("run_stone.ogg");
   24.36  	return true;
   24.37  }
   24.38  
    25.1 --- a/prototype/src/tile.h	Sun Sep 16 08:16:50 2012 +0300
    25.2 +++ b/prototype/src/tile.h	Mon Sep 17 08:40:59 2012 +0300
    25.3 @@ -7,6 +7,7 @@
    25.4  #include <psys/psys.h>
    25.5  #include "mesh.h"
    25.6  #include "light.h"
    25.7 +#include "audio/sample.h"
    25.8  
    25.9  enum {
   25.10  	TILE_NORTH	= 1,
   25.11 @@ -16,12 +17,21 @@
   25.12  	TILE_ALL	= 0xffff
   25.13  };
   25.14  
   25.15 +enum {
   25.16 +	TILE_SAMPLE_WALK,
   25.17 +	TILE_SAMPLE_RUN,
   25.18 +
   25.19 +	MAX_TILE_SAMPLES
   25.20 +};
   25.21 +
   25.22  class TileSet;
   25.23  
   25.24  class Tile {
   25.25  private:
   25.26  	TileSet *tset;
   25.27  
   25.28 +	AudioSample *samples[MAX_TILE_SAMPLES];
   25.29 +
   25.30  	std::vector<Mesh*> meshes;
   25.31  	std::vector<unsigned int> mesh_side, light_side, psys_side;
   25.32  	std::vector<Light*> lights;
   25.33 @@ -38,6 +48,8 @@
   25.34  	Tile(TileSet *tileset = 0);
   25.35  	~Tile();
   25.36  
   25.37 +	AudioSample *get_sample(int sidx) const;
   25.38 +
   25.39  	const struct psys_attributes * const *get_unique_psys() const;
   25.40  	int get_unique_psys_count() const;
   25.41  
    26.1 --- a/prototype/src/tileset.cc	Sun Sep 16 08:16:50 2012 +0300
    26.2 +++ b/prototype/src/tileset.cc	Mon Sep 17 08:40:59 2012 +0300
    26.3 @@ -6,6 +6,11 @@
    26.4  
    26.5  static TileSet *active_tileset;
    26.6  
    26.7 +TileSet::TileSet()
    26.8 +	: texset(load_texture, destroy_texture),
    26.9 +	  sampleset(load_audio_sample, destroy_audio_sample)
   26.10 +{
   26.11 +}
   26.12  
   26.13  TileSet::~TileSet()
   26.14  {
   26.15 @@ -66,6 +71,16 @@
   26.16  	return &texset;
   26.17  }
   26.18  
   26.19 +SampleSet *TileSet::get_samples()
   26.20 +{
   26.21 +	return &sampleset;
   26.22 +}
   26.23 +
   26.24 +const SampleSet *TileSet::get_samples() const
   26.25 +{
   26.26 +	return &sampleset;
   26.27 +}
   26.28 +
   26.29  Tile *TileSet::get_tile(const char *name) const
   26.30  {
   26.31  	auto res = tiles.find(name);
    27.1 --- a/prototype/src/tileset.h	Sun Sep 16 08:16:50 2012 +0300
    27.2 +++ b/prototype/src/tileset.h	Mon Sep 17 08:40:59 2012 +0300
    27.3 @@ -4,15 +4,18 @@
    27.4  #include <string>
    27.5  #include <map>
    27.6  #include "tile.h"
    27.7 -#include "texman.h"
    27.8 +#include "texture.h"
    27.9 +#include "audio/sample.h"
   27.10  
   27.11  class TileSet {
   27.12  private:
   27.13  	std::map<std::string, Tile*> tiles;
   27.14  
   27.15  	TextureSet texset;
   27.16 +	SampleSet sampleset;
   27.17  
   27.18  public:
   27.19 +	TileSet();
   27.20  	~TileSet();
   27.21  
   27.22  	bool load(const char *fname);
   27.23 @@ -20,6 +23,9 @@
   27.24  	TextureSet *get_textures();
   27.25  	const TextureSet *get_textures() const;
   27.26  
   27.27 +	SampleSet *get_samples();
   27.28 +	const SampleSet *get_samples() const;
   27.29 +
   27.30  	Tile *get_tile(const char *name) const;
   27.31  
   27.32  	void update_tiles(unsigned long msec);