3dphotoshoot

changeset 17:aef7f51f6397

resource loading works
author John Tsiombikas <nuclear@member.fsf.org>
date Wed, 10 Jun 2015 06:56:27 +0300
parents c6952cc82cca
children dccbd7d65517
files src/android/assman.c src/assman.h src/game.c src/rbtree.c src/rbtree.h src/sdr.c src/texture.c src/texture.h
diffstat 8 files changed, 867 insertions(+), 33 deletions(-) [+]
line diff
     1.1 --- a/src/android/assman.c	Tue Jun 09 18:38:33 2015 +0300
     1.2 +++ b/src/android/assman.c	Wed Jun 10 06:56:27 2015 +0300
     1.3 @@ -4,11 +4,39 @@
     1.4  #include "native_glue.h"
     1.5  #include "amain.h"
     1.6  
     1.7 -ass_file *ass_fopen(const char *fname)
     1.8 +ass_file *ass_fopen(const char *fname, const char *mode)
     1.9  {
    1.10  	AAsset *ass;
    1.11 +	unsigned int flags = 0;
    1.12 +	char prev = 0;
    1.13  
    1.14 -	if(!(ass = AAssetManager_open(app->activity->assetManager, fname, O_RDONLY))) {
    1.15 +	while(*mode) {
    1.16 +		switch(*mode) {
    1.17 +		case 'r':
    1.18 +			flags |= O_RDONLY;
    1.19 +			break;
    1.20 +
    1.21 +		case 'w':
    1.22 +			flags |= O_WRONLY;
    1.23 +			break;
    1.24 +
    1.25 +		case 'a':
    1.26 +			flags |= O_APPEND;
    1.27 +			break;
    1.28 +
    1.29 +		case '+':
    1.30 +			if(prev == 'w' || prev == 'a') {
    1.31 +				flags |= O_CREAT;
    1.32 +			}
    1.33 +			break;
    1.34 +
    1.35 +		default:
    1.36 +			break;
    1.37 +		}
    1.38 +		prev = *mode++;
    1.39 +	}
    1.40 +
    1.41 +	if(!(ass = AAssetManager_open(app->activity->assetManager, fname, flags))) {
    1.42  		return 0;
    1.43  	}
    1.44  	return (ass_file*)ass;
     2.1 --- a/src/assman.h	Tue Jun 09 18:38:33 2015 +0300
     2.2 +++ b/src/assman.h	Wed Jun 10 06:56:27 2015 +0300
     2.3 @@ -5,7 +5,7 @@
     2.4  
     2.5  typedef void ass_file;
     2.6  
     2.7 -ass_file *ass_fopen(const char *fname);
     2.8 +ass_file *ass_fopen(const char *fname, const char *mode);
     2.9  void ass_fclose(ass_file *fp);
    2.10  long ass_fseek(ass_file *fp, long offs, int whence);
    2.11  
     3.1 --- a/src/game.c	Tue Jun 09 18:38:33 2015 +0300
     3.2 +++ b/src/game.c	Wed Jun 10 06:56:27 2015 +0300
     3.3 @@ -7,15 +7,19 @@
     3.4  #include "camera.h"
     3.5  #include "sdr.h"
     3.6  #include "sanegl.h"
     3.7 +#include "texture.h"
     3.8  
     3.9 -static void draw_quad(float hsz, float vsz);
    3.10 +static void draw_quad(float hsz, float vsz, unsigned int sdr);
    3.11  
    3.12  static int win_width, win_height;
    3.13  static float win_aspect;
    3.14  static int video_width, video_height;
    3.15  static float video_aspect;
    3.16 -static unsigned int sdrprog;
    3.17 -static int aloc_vertex, aloc_texcoord, uloc_tex;
    3.18 +static unsigned int sdrprog, sdrprog_test;
    3.19 +static int uloc_tex, uloc_test_tex;
    3.20 +static struct texture *test_tex;
    3.21 +
    3.22 +enum { ATTR_VERTEX, ATTR_TEXCOORD };
    3.23  
    3.24  static const char *vsdr_source =
    3.25  	"attribute vec4 attr_vertex, attr_texcoord;\n"
    3.26 @@ -28,7 +32,7 @@
    3.27  	"\ttex_coords = matrix_texture * attr_texcoord;\n"
    3.28  	"}\n";
    3.29  
    3.30 -static const char *psdr_source =
    3.31 +static const char *psdr_cam_source =
    3.32  	"#extension GL_OES_EGL_image_external : require\n"
    3.33  	"precision mediump float;\n"
    3.34  	"uniform samplerExternalOES tex;\n"
    3.35 @@ -39,12 +43,21 @@
    3.36  	"\tgl_FragColor = vec4(texel.xyz, 1.0);\n"
    3.37  	"}\n";
    3.38  
    3.39 +static const char *psdr_tex_source =
    3.40 +	"precision mediump float;\n"
    3.41 +	"uniform sampler2D tex;\n"
    3.42 +	"varying vec4 tex_coords;\n"
    3.43 +	"void main()\n"
    3.44 +	"{\n"
    3.45 +	"\tvec4 texel = texture2D(tex, tex_coords.xy);\n"
    3.46 +	"\tgl_FragColor = texel;\n"
    3.47 +	"}\n";
    3.48  
    3.49  int game_init(void)
    3.50  {
    3.51 -	unsigned int vsdr, psdr;
    3.52 +	unsigned int vsdr, psdr_cam, psdr_tex;
    3.53  
    3.54 -	glEnable(GL_DEPTH_TEST);
    3.55 +	//glEnable(GL_DEPTH_TEST);
    3.56  	glEnable(GL_CULL_FACE);
    3.57  
    3.58  	glClearColor(0.4, 0.4, 0.4, 1);
    3.59 @@ -52,17 +65,36 @@
    3.60  	if(!(vsdr = create_vertex_shader(vsdr_source)))
    3.61  		return -1;
    3.62  	assert(glGetError() == GL_NO_ERROR);
    3.63 -	if(!(psdr = create_pixel_shader(psdr_source)))
    3.64 +	if(!(psdr_cam = create_pixel_shader(psdr_cam_source)))
    3.65  		return -1;
    3.66  	assert(glGetError() == GL_NO_ERROR);
    3.67 -	if(!(sdrprog = create_program_link(vsdr, psdr))) {
    3.68 +	if(!(psdr_tex = create_pixel_shader(psdr_tex_source)))
    3.69 +		return -1;
    3.70 +	assert(glGetError() == GL_NO_ERROR);
    3.71 +	if(!(sdrprog = create_program_link(vsdr, psdr_cam, 0))) {
    3.72  		fprintf(stderr, "failed to create shader program\n");
    3.73  		return -1;
    3.74  	}
    3.75 +	if(!(sdrprog_test = create_program_link(vsdr, psdr_tex, 0))) {
    3.76 +		fprintf(stderr, "failed to create test shader program\n");
    3.77 +		return -1;
    3.78 +	}
    3.79 +
    3.80  	glUseProgram(sdrprog);
    3.81 -	aloc_vertex = glGetAttribLocation(sdrprog, "attr_vertex");
    3.82 -	aloc_texcoord = glGetAttribLocation(sdrprog, "attr_texcoord");
    3.83 +	glBindAttribLocation(sdrprog, ATTR_VERTEX, "attr_vertex");
    3.84 +	glBindAttribLocation(sdrprog, ATTR_TEXCOORD, "attr_texcoord");
    3.85  	uloc_tex = glGetUniformLocation(sdrprog, "tex");
    3.86 +	glLinkProgram(sdrprog);
    3.87 +
    3.88 +	glUseProgram(sdrprog_test);
    3.89 +	glBindAttribLocation(sdrprog_test, ATTR_VERTEX, "attr_vertex");
    3.90 +	glBindAttribLocation(sdrprog_test, ATTR_TEXCOORD, "attr_texcoord");
    3.91 +	uloc_test_tex = glGetUniformLocation(sdrprog_test, "tex");
    3.92 +	glLinkProgram(sdrprog_test);
    3.93 +
    3.94 +	if(!(test_tex = get_texture("data/opengl.png"))) {
    3.95 +		return -1;
    3.96 +	}
    3.97  
    3.98  	cam_start_video();
    3.99  	cam_video_size(&video_width, &video_height);
   3.100 @@ -94,7 +126,6 @@
   3.101  
   3.102  	//float tsec = (float)msec / 1000.0f;
   3.103  
   3.104 -	//glClearColor(sin(tsec * 10.0), cos(tsec * 10.0), -sin(tsec * 10.0), 1.0);
   3.105  	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
   3.106  
   3.107  	gl_matrix_mode(GL_MODELVIEW);
   3.108 @@ -115,37 +146,50 @@
   3.109  		xscale = video_aspect;
   3.110  		yscale = 1.0;
   3.111  	}
   3.112 -	draw_quad(xscale, yscale);
   3.113 +	draw_quad(xscale, yscale, sdrprog);
   3.114 +
   3.115 +	gl_matrix_mode(GL_TEXTURE);
   3.116 +	gl_load_identity();
   3.117 +	gl_translatef(0, 1, 0);
   3.118 +	gl_scalef(1, -1, 1);
   3.119 +	gl_matrix_mode(GL_MODELVIEW);
   3.120 +	gl_load_identity();
   3.121 +	gl_scalef((float)test_tex->width / (float)test_tex->height, 1, 1);
   3.122 +
   3.123 +	glUseProgram(sdrprog_test);
   3.124 +	glBindTexture(GL_TEXTURE_2D, test_tex->texid);
   3.125 +	if(uloc_test_tex >= 0) {
   3.126 +		glUniform1i(uloc_test_tex, 0);
   3.127 +	}
   3.128 +
   3.129 +	glEnable(GL_BLEND);
   3.130 +	glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
   3.131 +
   3.132 +	draw_quad(0.5, 0.5, sdrprog_test);
   3.133 +
   3.134 +	glDisable(GL_BLEND);
   3.135  }
   3.136  
   3.137 -static void draw_quad(float hsz, float vsz)
   3.138 +static void draw_quad(float hsz, float vsz, unsigned int sdr)
   3.139  {
   3.140  	static const float varr[] = {-1, -1, 1, -1, 1, 1, -1, 1};
   3.141  	static const float tcarr[] = {0, 0, 1, 0, 1, 1, 0, 1};
   3.142  
   3.143 -	if(aloc_vertex == -1) {
   3.144 -		return;
   3.145 -	}
   3.146 -
   3.147  	gl_matrix_mode(GL_MODELVIEW);
   3.148  	gl_push_matrix();
   3.149  	gl_scalef(hsz, vsz, 1);
   3.150  
   3.151 -	gl_apply_xform(sdrprog);
   3.152 +	gl_apply_xform(sdr);
   3.153  
   3.154 -	glEnableVertexAttribArray(aloc_vertex);
   3.155 -	glVertexAttribPointer(aloc_vertex, 2, GL_FLOAT, 0, 0, varr);
   3.156 -	if(aloc_texcoord != -1) {
   3.157 -		glEnableVertexAttribArray(aloc_texcoord);
   3.158 -		glVertexAttribPointer(aloc_texcoord, 2, GL_FLOAT, 0, 0, tcarr);
   3.159 -	}
   3.160 +	glEnableVertexAttribArray(ATTR_VERTEX);
   3.161 +	glEnableVertexAttribArray(ATTR_TEXCOORD);
   3.162 +	glVertexAttribPointer(ATTR_VERTEX, 2, GL_FLOAT, 0, 0, varr);
   3.163 +	glVertexAttribPointer(ATTR_TEXCOORD, 2, GL_FLOAT, 0, 0, tcarr);
   3.164  
   3.165  	glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
   3.166  
   3.167 -	glDisableVertexAttribArray(aloc_vertex);
   3.168 -	if(aloc_texcoord != -1) {
   3.169 -		glDisableVertexAttribArray(aloc_texcoord);
   3.170 -	}
   3.171 +	glDisableVertexAttribArray(ATTR_VERTEX);
   3.172 +	glDisableVertexAttribArray(ATTR_TEXCOORD);
   3.173  
   3.174  	gl_pop_matrix();
   3.175  }
     4.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     4.2 +++ b/src/rbtree.c	Wed Jun 10 06:56:27 2015 +0300
     4.3 @@ -0,0 +1,501 @@
     4.4 +/*
     4.5 +rbtree - simple balanced binary search tree (red-black tree) library.
     4.6 +Copyright (C) 2011-2014  John Tsiombikas <nuclear@member.fsf.org>
     4.7 +
     4.8 +rbtree is free software, feel free to use, modify, and redistribute it, under
     4.9 +the terms of the 3-clause BSD license. See COPYING for details.
    4.10 + */
    4.11 +#include <stdio.h>
    4.12 +#include <stdlib.h>
    4.13 +#include <stdint.h>
    4.14 +#include <string.h>
    4.15 +#include "rbtree.h"
    4.16 +
    4.17 +#define INT2PTR(x)	((void*)(intptr_t)(x))
    4.18 +#define PTR2INT(x)	((int)(intptr_t)(x))
    4.19 +
    4.20 +struct rbtree {
    4.21 +	struct rbnode *root;
    4.22 +
    4.23 +	rb_alloc_func_t alloc;
    4.24 +	rb_free_func_t free;
    4.25 +
    4.26 +	rb_cmp_func_t cmp;
    4.27 +	rb_del_func_t del;
    4.28 +	void *del_cls;
    4.29 +
    4.30 +	struct rbnode *rstack, *iter;
    4.31 +};
    4.32 +
    4.33 +static int cmpaddr(const void *ap, const void *bp);
    4.34 +static int cmpint(const void *ap, const void *bp);
    4.35 +
    4.36 +static int count_nodes(struct rbnode *node);
    4.37 +static void del_tree(struct rbnode *node, void (*delfunc)(struct rbnode*, void*), void *cls);
    4.38 +static struct rbnode *insert(struct rbtree *rb, struct rbnode *tree, void *key, void *data);
    4.39 +static struct rbnode *delete(struct rbtree *rb, struct rbnode *tree, void *key);
    4.40 +/*static struct rbnode *find(struct rbtree *rb, struct rbnode *node, void *key);*/
    4.41 +static void traverse(struct rbnode *node, void (*func)(struct rbnode*, void*), void *cls);
    4.42 +
    4.43 +struct rbtree *rb_create(rb_cmp_func_t cmp_func)
    4.44 +{
    4.45 +	struct rbtree *rb;
    4.46 +
    4.47 +	if(!(rb = malloc(sizeof *rb))) {
    4.48 +		return 0;
    4.49 +	}
    4.50 +	if(rb_init(rb, cmp_func) == -1) {
    4.51 +		free(rb);
    4.52 +		return 0;
    4.53 +	}
    4.54 +	return rb;
    4.55 +}
    4.56 +
    4.57 +void rb_free(struct rbtree *rb)
    4.58 +{
    4.59 +	rb_destroy(rb);
    4.60 +	free(rb);
    4.61 +}
    4.62 +
    4.63 +
    4.64 +int rb_init(struct rbtree *rb, rb_cmp_func_t cmp_func)
    4.65 +{
    4.66 +	memset(rb, 0, sizeof *rb);
    4.67 +
    4.68 +	if(!cmp_func) {
    4.69 +		rb->cmp = cmpaddr;
    4.70 +	} else if(cmp_func == RB_KEY_INT) {
    4.71 +		rb->cmp = cmpint;
    4.72 +	} else if(cmp_func == RB_KEY_STRING) {
    4.73 +		rb->cmp = (rb_cmp_func_t)strcmp;
    4.74 +	} else {
    4.75 +		rb->cmp = cmp_func;
    4.76 +	}
    4.77 +
    4.78 +	rb->alloc = malloc;
    4.79 +	rb->free = free;
    4.80 +	return 0;
    4.81 +}
    4.82 +
    4.83 +void rb_destroy(struct rbtree *rb)
    4.84 +{
    4.85 +	del_tree(rb->root, rb->del, rb->del_cls);
    4.86 +}
    4.87 +
    4.88 +void rb_set_allocator(struct rbtree *rb, rb_alloc_func_t alloc, rb_free_func_t free)
    4.89 +{
    4.90 +	rb->alloc = alloc;
    4.91 +	rb->free = free;
    4.92 +}
    4.93 +
    4.94 +
    4.95 +void rb_set_compare_func(struct rbtree *rb, rb_cmp_func_t func)
    4.96 +{
    4.97 +	rb->cmp = func;
    4.98 +}
    4.99 +
   4.100 +void rb_set_delete_func(struct rbtree *rb, rb_del_func_t func, void *cls)
   4.101 +{
   4.102 +	rb->del = func;
   4.103 +	rb->del_cls = cls;
   4.104 +}
   4.105 +
   4.106 +
   4.107 +void rb_clear(struct rbtree *rb)
   4.108 +{
   4.109 +	del_tree(rb->root, rb->del, rb->del_cls);
   4.110 +	rb->root = 0;
   4.111 +}
   4.112 +
   4.113 +int rb_copy(struct rbtree *dest, struct rbtree *src)
   4.114 +{
   4.115 +	struct rbnode *node;
   4.116 +
   4.117 +	rb_clear(dest);
   4.118 +	rb_begin(src);
   4.119 +	while((node = rb_next(src))) {
   4.120 +		if(rb_insert(dest, node->key, node->data) == -1) {
   4.121 +			return -1;
   4.122 +		}
   4.123 +	}
   4.124 +	return 0;
   4.125 +}
   4.126 +
   4.127 +int rb_size(struct rbtree *rb)
   4.128 +{
   4.129 +	return count_nodes(rb->root);
   4.130 +}
   4.131 +
   4.132 +int rb_insert(struct rbtree *rb, void *key, void *data)
   4.133 +{
   4.134 +	rb->root = insert(rb, rb->root, key, data);
   4.135 +	rb->root->red = 0;
   4.136 +	return 0;
   4.137 +}
   4.138 +
   4.139 +int rb_inserti(struct rbtree *rb, int key, void *data)
   4.140 +{
   4.141 +	rb->root = insert(rb, rb->root, INT2PTR(key), data);
   4.142 +	rb->root->red = 0;
   4.143 +	return 0;
   4.144 +}
   4.145 +
   4.146 +
   4.147 +int rb_delete(struct rbtree *rb, void *key)
   4.148 +{
   4.149 +	rb->root = delete(rb, rb->root, key);
   4.150 +	rb->root->red = 0;
   4.151 +	return 0;
   4.152 +}
   4.153 +
   4.154 +int rb_deletei(struct rbtree *rb, int key)
   4.155 +{
   4.156 +	rb->root = delete(rb, rb->root, INT2PTR(key));
   4.157 +	rb->root->red = 0;
   4.158 +	return 0;
   4.159 +}
   4.160 +
   4.161 +
   4.162 +struct rbnode *rb_find(struct rbtree *rb, void *key)
   4.163 +{
   4.164 +	struct rbnode *node = rb->root;
   4.165 +
   4.166 +	while(node) {
   4.167 +		int cmp = rb->cmp(key, node->key);
   4.168 +		if(cmp == 0) {
   4.169 +			return node;
   4.170 +		}
   4.171 +		node = cmp < 0 ? node->left : node->right;
   4.172 +	}
   4.173 +	return 0;
   4.174 +}
   4.175 +
   4.176 +struct rbnode *rb_findi(struct rbtree *rb, int key)
   4.177 +{
   4.178 +	return rb_find(rb, INT2PTR(key));
   4.179 +}
   4.180 +
   4.181 +
   4.182 +void rb_foreach(struct rbtree *rb, void (*func)(struct rbnode*, void*), void *cls)
   4.183 +{
   4.184 +	traverse(rb->root, func, cls);
   4.185 +}
   4.186 +
   4.187 +
   4.188 +struct rbnode *rb_root(struct rbtree *rb)
   4.189 +{
   4.190 +	return rb->root;
   4.191 +}
   4.192 +
   4.193 +void rb_begin(struct rbtree *rb)
   4.194 +{
   4.195 +	rb->rstack = 0;
   4.196 +	rb->iter = rb->root;
   4.197 +}
   4.198 +
   4.199 +#define push(sp, x)		((x)->next = (sp), (sp) = (x))
   4.200 +#define pop(sp)			((sp) = (sp)->next)
   4.201 +#define top(sp)			(sp)
   4.202 +
   4.203 +struct rbnode *rb_next(struct rbtree *rb)
   4.204 +{
   4.205 +	struct rbnode *res = 0;
   4.206 +
   4.207 +	while(rb->rstack || rb->iter) {
   4.208 +		if(rb->iter) {
   4.209 +			push(rb->rstack, rb->iter);
   4.210 +			rb->iter = rb->iter->left;
   4.211 +		} else {
   4.212 +			rb->iter = top(rb->rstack);
   4.213 +			pop(rb->rstack);
   4.214 +			res = rb->iter;
   4.215 +			rb->iter = rb->iter->right;
   4.216 +			break;
   4.217 +		}
   4.218 +	}
   4.219 +	return res;
   4.220 +}
   4.221 +
   4.222 +void *rb_node_key(struct rbnode *node)
   4.223 +{
   4.224 +	return node ? node->key : 0;
   4.225 +}
   4.226 +
   4.227 +int rb_node_keyi(struct rbnode *node)
   4.228 +{
   4.229 +	return node ? PTR2INT(node->key) : 0;
   4.230 +}
   4.231 +
   4.232 +void *rb_node_data(struct rbnode *node)
   4.233 +{
   4.234 +	return node ? node->data : 0;
   4.235 +}
   4.236 +
   4.237 +static int cmpaddr(const void *ap, const void *bp)
   4.238 +{
   4.239 +	return ap < bp ? -1 : (ap > bp ? 1 : 0);
   4.240 +}
   4.241 +
   4.242 +static int cmpint(const void *ap, const void *bp)
   4.243 +{
   4.244 +	return PTR2INT(ap) - PTR2INT(bp);
   4.245 +}
   4.246 +
   4.247 +
   4.248 +/* ---- left-leaning 2-3 red-black implementation ---- */
   4.249 +
   4.250 +/* helper prototypes */
   4.251 +static int is_red(struct rbnode *tree);
   4.252 +static void color_flip(struct rbnode *tree);
   4.253 +static struct rbnode *rot_left(struct rbnode *a);
   4.254 +static struct rbnode *rot_right(struct rbnode *a);
   4.255 +static struct rbnode *find_min(struct rbnode *tree);
   4.256 +static struct rbnode *del_min(struct rbtree *rb, struct rbnode *tree);
   4.257 +/*static struct rbnode *move_red_right(struct rbnode *tree);*/
   4.258 +static struct rbnode *move_red_left(struct rbnode *tree);
   4.259 +static struct rbnode *fix_up(struct rbnode *tree);
   4.260 +
   4.261 +static int count_nodes(struct rbnode *node)
   4.262 +{
   4.263 +	if(!node)
   4.264 +		return 0;
   4.265 +
   4.266 +	return 1 + count_nodes(node->left) + count_nodes(node->right);
   4.267 +}
   4.268 +
   4.269 +static void del_tree(struct rbnode *node, rb_del_func_t delfunc, void *cls)
   4.270 +{
   4.271 +	if(!node)
   4.272 +		return;
   4.273 +
   4.274 +	del_tree(node->left, delfunc, cls);
   4.275 +	del_tree(node->right, delfunc, cls);
   4.276 +
   4.277 +	if(delfunc) {
   4.278 +		delfunc(node, cls);
   4.279 +	}
   4.280 +	free(node);
   4.281 +}
   4.282 +
   4.283 +static struct rbnode *insert(struct rbtree *rb, struct rbnode *tree, void *key, void *data)
   4.284 +{
   4.285 +	int cmp;
   4.286 +
   4.287 +	if(!tree) {
   4.288 +		struct rbnode *node = rb->alloc(sizeof *node);
   4.289 +		node->red = 1;
   4.290 +		node->key = key;
   4.291 +		node->data = data;
   4.292 +		node->left = node->right = 0;
   4.293 +		return node;
   4.294 +	}
   4.295 +
   4.296 +	cmp = rb->cmp(key, tree->key);
   4.297 +
   4.298 +	if(cmp < 0) {
   4.299 +		tree->left = insert(rb, tree->left, key, data);
   4.300 +	} else if(cmp > 0) {
   4.301 +		tree->right = insert(rb, tree->right, key, data);
   4.302 +	} else {
   4.303 +		tree->data = data;
   4.304 +	}
   4.305 +
   4.306 +	/* fix right-leaning reds */
   4.307 +	if(is_red(tree->right)) {
   4.308 +		tree = rot_left(tree);
   4.309 +	}
   4.310 +	/* fix two reds in a row */
   4.311 +	if(is_red(tree->left) && is_red(tree->left->left)) {
   4.312 +		tree = rot_right(tree);
   4.313 +	}
   4.314 +
   4.315 +	/* if 4-node, split it by color inversion */
   4.316 +	if(is_red(tree->left) && is_red(tree->right)) {
   4.317 +		color_flip(tree);
   4.318 +	}
   4.319 +
   4.320 +	return tree;
   4.321 +}
   4.322 +
   4.323 +static struct rbnode *delete(struct rbtree *rb, struct rbnode *tree, void *key)
   4.324 +{
   4.325 +	int cmp;
   4.326 +
   4.327 +	if(!tree) {
   4.328 +		return 0;
   4.329 +	}
   4.330 +
   4.331 +	cmp = rb->cmp(key, tree->key);
   4.332 +
   4.333 +	if(cmp < 0) {
   4.334 +		if(!is_red(tree->left) && !is_red(tree->left->left)) {
   4.335 +			tree = move_red_left(tree);
   4.336 +		}
   4.337 +		tree->left = delete(rb, tree->left, key);
   4.338 +	} else {
   4.339 +		/* need reds on the right */
   4.340 +		if(is_red(tree->left)) {
   4.341 +			tree = rot_right(tree);
   4.342 +		}
   4.343 +
   4.344 +		/* found it at the bottom (XXX what certifies left is null?) */
   4.345 +		if(cmp == 0 && !tree->right) {
   4.346 +			if(rb->del) {
   4.347 +				rb->del(tree, rb->del_cls);
   4.348 +			}
   4.349 +			rb->free(tree);
   4.350 +			return 0;
   4.351 +		}
   4.352 +
   4.353 +		if(!is_red(tree->right) && !is_red(tree->right->left)) {
   4.354 +			tree = move_red_left(tree);
   4.355 +		}
   4.356 +
   4.357 +		if(key == tree->key) {
   4.358 +			struct rbnode *rmin = find_min(tree->right);
   4.359 +			tree->key = rmin->key;
   4.360 +			tree->data = rmin->data;
   4.361 +			tree->right = del_min(rb, tree->right);
   4.362 +		} else {
   4.363 +			tree->right = delete(rb, tree->right, key);
   4.364 +		}
   4.365 +	}
   4.366 +
   4.367 +	return fix_up(tree);
   4.368 +}
   4.369 +
   4.370 +/*static struct rbnode *find(struct rbtree *rb, struct rbnode *node, void *key)
   4.371 +{
   4.372 +	int cmp;
   4.373 +
   4.374 +	if(!node)
   4.375 +		return 0;
   4.376 +
   4.377 +	if((cmp = rb->cmp(key, node->key)) == 0) {
   4.378 +		return node;
   4.379 +	}
   4.380 +	return find(rb, cmp < 0 ? node->left : node->right, key);
   4.381 +}*/
   4.382 +
   4.383 +static void traverse(struct rbnode *node, void (*func)(struct rbnode*, void*), void *cls)
   4.384 +{
   4.385 +	if(!node)
   4.386 +		return;
   4.387 +
   4.388 +	traverse(node->left, func, cls);
   4.389 +	func(node, cls);
   4.390 +	traverse(node->right, func, cls);
   4.391 +}
   4.392 +
   4.393 +/* helpers */
   4.394 +
   4.395 +static int is_red(struct rbnode *tree)
   4.396 +{
   4.397 +	return tree && tree->red;
   4.398 +}
   4.399 +
   4.400 +static void color_flip(struct rbnode *tree)
   4.401 +{
   4.402 +	tree->red = !tree->red;
   4.403 +	tree->left->red = !tree->left->red;
   4.404 +	tree->right->red = !tree->right->red;
   4.405 +}
   4.406 +
   4.407 +static struct rbnode *rot_left(struct rbnode *a)
   4.408 +{
   4.409 +	struct rbnode *b = a->right;
   4.410 +	a->right = b->left;
   4.411 +	b->left = a;
   4.412 +	b->red = a->red;
   4.413 +	a->red = 1;
   4.414 +	return b;
   4.415 +}
   4.416 +
   4.417 +static struct rbnode *rot_right(struct rbnode *a)
   4.418 +{
   4.419 +	struct rbnode *b = a->left;
   4.420 +	a->left = b->right;
   4.421 +	b->right = a;
   4.422 +	b->red = a->red;
   4.423 +	a->red = 1;
   4.424 +	return b;
   4.425 +}
   4.426 +
   4.427 +static struct rbnode *find_min(struct rbnode *tree)
   4.428 +{
   4.429 +	if(!tree)
   4.430 +		return 0;
   4.431 +
   4.432 +	while(tree->left) {
   4.433 +		tree = tree->left;
   4.434 +	}
   4.435 +	return tree;
   4.436 +}
   4.437 +
   4.438 +static struct rbnode *del_min(struct rbtree *rb, struct rbnode *tree)
   4.439 +{
   4.440 +	if(!tree->left) {
   4.441 +		if(rb->del) {
   4.442 +			rb->del(tree->left, rb->del_cls);
   4.443 +		}
   4.444 +		rb->free(tree->left);
   4.445 +		return 0;
   4.446 +	}
   4.447 +
   4.448 +	/* make sure we've got red (3/4-nodes) at the left side so we can delete at the bottom */
   4.449 +	if(!is_red(tree->left) && !is_red(tree->left->left)) {
   4.450 +		tree = move_red_left(tree);
   4.451 +	}
   4.452 +	tree->left = del_min(rb, tree->left);
   4.453 +
   4.454 +	/* fix right-reds, red-reds, and split 4-nodes on the way up */
   4.455 +	return fix_up(tree);
   4.456 +}
   4.457 +
   4.458 +#if 0
   4.459 +/* push a red link on this node to the right */
   4.460 +static struct rbnode *move_red_right(struct rbnode *tree)
   4.461 +{
   4.462 +	/* flipping it makes both children go red, so we have a red to the right */
   4.463 +	color_flip(tree);
   4.464 +
   4.465 +	/* if after the flip we've got a red-red situation to the left, fix it */
   4.466 +	if(is_red(tree->left->left)) {
   4.467 +		tree = rot_right(tree);
   4.468 +		color_flip(tree);
   4.469 +	}
   4.470 +	return tree;
   4.471 +}
   4.472 +#endif
   4.473 +
   4.474 +/* push a red link on this node to the left */
   4.475 +static struct rbnode *move_red_left(struct rbnode *tree)
   4.476 +{
   4.477 +	/* flipping it makes both children go red, so we have a red to the left */
   4.478 +	color_flip(tree);
   4.479 +
   4.480 +	/* if after the flip we've got a red-red on the right-left, fix it */
   4.481 +	if(is_red(tree->right->left)) {
   4.482 +		tree->right = rot_right(tree->right);
   4.483 +		tree = rot_left(tree);
   4.484 +		color_flip(tree);
   4.485 +	}
   4.486 +	return tree;
   4.487 +}
   4.488 +
   4.489 +static struct rbnode *fix_up(struct rbnode *tree)
   4.490 +{
   4.491 +	/* fix right-leaning */
   4.492 +	if(is_red(tree->right)) {
   4.493 +		tree = rot_left(tree);
   4.494 +	}
   4.495 +	/* change invalid red-red pairs into a proper 4-node */
   4.496 +	if(is_red(tree->left) && is_red(tree->left->left)) {
   4.497 +		tree = rot_right(tree);
   4.498 +	}
   4.499 +	/* split 4-nodes */
   4.500 +	if(is_red(tree->left) && is_red(tree->right)) {
   4.501 +		color_flip(tree);
   4.502 +	}
   4.503 +	return tree;
   4.504 +}
     5.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     5.2 +++ b/src/rbtree.h	Wed Jun 10 06:56:27 2015 +0300
     5.3 @@ -0,0 +1,78 @@
     5.4 +/*
     5.5 +rbtree - simple balanced binary search tree (red-black tree) library.
     5.6 +Copyright (C) 2011-2014  John Tsiombikas <nuclear@member.fsf.org>
     5.7 +
     5.8 +rbtree is free software, feel free to use, modify, and redistribute it, under
     5.9 +the terms of the 3-clause BSD license. See COPYING for details.
    5.10 + */
    5.11 +#ifndef RBTREE_H_
    5.12 +#define RBTREE_H_
    5.13 +
    5.14 +struct rbtree;
    5.15 +
    5.16 +
    5.17 +struct rbnode {
    5.18 +	void *key, *data;
    5.19 +	int red;
    5.20 +	struct rbnode *left, *right;
    5.21 +	struct rbnode *next;	/* for iterator stack */
    5.22 +};
    5.23 +
    5.24 +
    5.25 +typedef void *(*rb_alloc_func_t)(size_t);
    5.26 +typedef void (*rb_free_func_t)(void*);
    5.27 +
    5.28 +typedef int (*rb_cmp_func_t)(const void*, const void*);
    5.29 +typedef void (*rb_del_func_t)(struct rbnode*, void*);
    5.30 +
    5.31 +#define RB_KEY_ADDR		(rb_cmp_func_t)(0)
    5.32 +#define RB_KEY_INT		(rb_cmp_func_t)(1)
    5.33 +#define RB_KEY_STRING	(rb_cmp_func_t)(3)
    5.34 +
    5.35 +
    5.36 +#ifdef __cplusplus
    5.37 +extern "C" {
    5.38 +#endif
    5.39 +
    5.40 +struct rbtree *rb_create(rb_cmp_func_t cmp_func);
    5.41 +void rb_free(struct rbtree *rb);
    5.42 +
    5.43 +int rb_init(struct rbtree *rb, rb_cmp_func_t cmp_func);
    5.44 +void rb_destroy(struct rbtree *rb);
    5.45 +
    5.46 +void rb_set_allocator(struct rbtree *rb, rb_alloc_func_t alloc, rb_free_func_t free);
    5.47 +void rb_set_compare_func(struct rbtree *rb, rb_cmp_func_t func);
    5.48 +void rb_set_delete_func(struct rbtree *rb, rb_del_func_t func, void *cls);
    5.49 +/* TODO add user deep copy function */
    5.50 +
    5.51 +void rb_clear(struct rbtree *rb);
    5.52 +int rb_copy(struct rbtree *dest, struct rbtree *src);
    5.53 +
    5.54 +int rb_size(struct rbtree *rb);
    5.55 +
    5.56 +int rb_insert(struct rbtree *rb, void *key, void *data);
    5.57 +int rb_inserti(struct rbtree *rb, int key, void *data);
    5.58 +
    5.59 +int rb_delete(struct rbtree *rb, void *key);
    5.60 +int rb_deletei(struct rbtree *rb, int key);
    5.61 +
    5.62 +struct rbnode *rb_find(struct rbtree *rb, void *key);
    5.63 +struct rbnode *rb_findi(struct rbtree *rb, int key);
    5.64 +
    5.65 +void rb_foreach(struct rbtree *rb, void (*func)(struct rbnode*, void*), void *cls);
    5.66 +
    5.67 +struct rbnode *rb_root(struct rbtree *rb);
    5.68 +
    5.69 +void rb_begin(struct rbtree *rb);
    5.70 +struct rbnode *rb_next(struct rbtree *rb);
    5.71 +
    5.72 +void *rb_node_key(struct rbnode *node);
    5.73 +int rb_node_keyi(struct rbnode *node);
    5.74 +void *rb_node_data(struct rbnode *node);
    5.75 +
    5.76 +#ifdef __cplusplus
    5.77 +}
    5.78 +#endif
    5.79 +
    5.80 +
    5.81 +#endif	/* RBTREE_H_ */
     6.1 --- a/src/sdr.c	Tue Jun 09 18:38:33 2015 +0300
     6.2 +++ b/src/sdr.c	Wed Jun 10 06:56:27 2015 +0300
     6.3 @@ -233,10 +233,13 @@
     6.4  
     6.5  void attach_shader(unsigned int prog, unsigned int sdr)
     6.6  {
     6.7 +	int err;
     6.8 +
     6.9  	if(prog && sdr) {
    6.10 +		assert(glGetError() == GL_NO_ERROR);
    6.11  		glAttachShader(prog, sdr);
    6.12 -		if(glGetError() != GL_NO_ERROR) {
    6.13 -			fprintf(stderr, "failed to attach shader %u to program %u\n", sdr, prog);
    6.14 +		if((err = glGetError()) != GL_NO_ERROR) {
    6.15 +			fprintf(stderr, "failed to attach shader %u to program %u (err: 0x%x)\n", sdr, prog, err);
    6.16  			abort();
    6.17  		}
    6.18  	}
     7.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     7.2 +++ b/src/texture.c	Wed Jun 10 06:56:27 2015 +0300
     7.3 @@ -0,0 +1,165 @@
     7.4 +#include <stdio.h>
     7.5 +#include <stdlib.h>
     7.6 +#include <string.h>
     7.7 +#include <errno.h>
     7.8 +#include <assert.h>
     7.9 +#include "opengl.h"
    7.10 +#include "texture.h"
    7.11 +#include "imago2.h"
    7.12 +#include "rbtree.h"
    7.13 +#include "assman.h"
    7.14 +
    7.15 +static size_t ioread(void *buf, size_t bytes, void *uptr);
    7.16 +static long ioseek(long offs, int whence, void *uptr);
    7.17 +static unsigned int next_pow2(unsigned int x);
    7.18 +
    7.19 +static struct rbtree *texdb;
    7.20 +
    7.21 +int load_texture(struct texture *tex, const char *fname)
    7.22 +{
    7.23 +	struct img_pixmap img;
    7.24 +	struct img_io io;
    7.25 +	ass_file *fp;
    7.26 +
    7.27 +	printf("loading texture: %s\n", fname);
    7.28 +
    7.29 +	if(!(fp = ass_fopen(fname, "rb"))) {
    7.30 +		fprintf(stderr, "failed to open texture file: %s: %s\n", fname, strerror(errno));
    7.31 +		return -1;
    7.32 +	}
    7.33 +	io.uptr = fp;
    7.34 +	io.read = ioread;
    7.35 +	io.write = 0;
    7.36 +	io.seek = ioseek;
    7.37 +
    7.38 +	img_init(&img);
    7.39 +	if(img_read(&img, &io) == -1) {
    7.40 +		fprintf(stderr, "failed to load texture file: %s\n", fname);
    7.41 +		ass_fclose(fp);
    7.42 +		return -1;
    7.43 +	}
    7.44 +	img_convert(&img, IMG_FMT_RGBA32);
    7.45 +
    7.46 +	tex->img_width = img.width;
    7.47 +	tex->img_height = img.height;
    7.48 +	tex->width = next_pow2(img.width);
    7.49 +	tex->height = next_pow2(img.height);
    7.50 +
    7.51 +	printf("    %dx%d (tex: %dx%d)\n", tex->img_width, tex->img_height, tex->width, tex->height);
    7.52 +
    7.53 +	glGenTextures(1, &tex->texid);
    7.54 +	glBindTexture(GL_TEXTURE_2D, tex->texid);
    7.55 +	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
    7.56 +	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    7.57 +
    7.58 +#ifdef __GLEW_H__
    7.59 +	if(GLEW_SGIS_generate_mipmap) {
    7.60 +		glTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP_SGIS, GL_TRUE);
    7.61 +#endif
    7.62 +		glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, tex->width, tex->height, 0,
    7.63 +				GL_RGBA, GL_UNSIGNED_BYTE, img.pixels);
    7.64 +#ifdef __GLEW_H__
    7.65 +	} else {
    7.66 +		gluBuild2DMipmaps(GL_TEXTURE_2D, GL_RGBA, tex->width, tex->height,
    7.67 +				GL_RGBA, GL_UNSIGNED_BYTE, img.pixels);
    7.68 +	}
    7.69 +#endif
    7.70 +
    7.71 +#ifdef GL_ES_VERSION_2_0
    7.72 +	glGenerateMipmap(GL_TEXTURE_2D);
    7.73 +#endif
    7.74 +
    7.75 +	return 0;
    7.76 +}
    7.77 +
    7.78 +struct texture *get_texture(const char *fname)
    7.79 +{
    7.80 +	struct texture *tex;
    7.81 +	struct rbnode *node;
    7.82 +
    7.83 +	if(!(texdb = rb_create(RB_KEY_STRING))) {
    7.84 +		static int err_printed;
    7.85 +		if(!err_printed) {
    7.86 +			fprintf(stderr, "failed to create texture database\n");
    7.87 +			err_printed = 1;
    7.88 +		}
    7.89 +		return 0;
    7.90 +	}
    7.91 +
    7.92 +	if((node = rb_find(texdb, (void*)fname))) {
    7.93 +		return rb_node_data(node);
    7.94 +	}
    7.95 +
    7.96 +	if(!(tex = malloc(sizeof *tex))) {
    7.97 +		fprintf(stderr, "failed to load texture \"%s\": %s\n", fname, strerror(errno));
    7.98 +		return 0;
    7.99 +	}
   7.100 +	if(load_texture(tex, fname) == -1) {
   7.101 +		free(tex);
   7.102 +		return 0;
   7.103 +	}
   7.104 +
   7.105 +	if(rb_insert(texdb, (void*)fname, tex) == -1) {
   7.106 +		fprintf(stderr, "failed to insert texture into the texture database\n");
   7.107 +	}
   7.108 +	return tex;
   7.109 +}
   7.110 +
   7.111 +
   7.112 +#define DBG_TEX_SZ	64
   7.113 +int gen_debug_texture(struct texture *tex)
   7.114 +{
   7.115 +	static unsigned char *pixels;
   7.116 +
   7.117 +	if(!pixels) {
   7.118 +		int i, j;
   7.119 +		unsigned char *pptr;
   7.120 +		pptr = pixels = malloc(DBG_TEX_SZ * DBG_TEX_SZ * 4);
   7.121 +		assert(pixels);
   7.122 +
   7.123 +		for(i=0; i<DBG_TEX_SZ; i++) {
   7.124 +			for(j=0; j<DBG_TEX_SZ; j++) {
   7.125 +				int chess = ((j >> 3) & 1) == ((i >> 3) & 1);
   7.126 +				*pptr++ = chess ? 255 : 64;
   7.127 +				*pptr++ = 128;
   7.128 +				*pptr++ = chess ? 64 : 255;
   7.129 +				*pptr++ = 255;	/* alpha */
   7.130 +			}
   7.131 +		}
   7.132 +	}
   7.133 +
   7.134 +	if(!tex->texid) {
   7.135 +		glGenTextures(1, &tex->texid);
   7.136 +	}
   7.137 +
   7.138 +	glBindTexture(GL_TEXTURE_2D, tex->texid);
   7.139 +	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
   7.140 +	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
   7.141 +	glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, DBG_TEX_SZ, DBG_TEX_SZ, 0, GL_RGBA,
   7.142 +			GL_UNSIGNED_BYTE, pixels);
   7.143 +
   7.144 +	tex->width = tex->img_width = tex->height = tex->img_height = DBG_TEX_SZ;
   7.145 +	return 0;
   7.146 +}
   7.147 +
   7.148 +
   7.149 +static size_t ioread(void *buf, size_t bytes, void *uptr)
   7.150 +{
   7.151 +	return ass_fread(buf, 1, bytes, uptr);
   7.152 +}
   7.153 +
   7.154 +static long ioseek(long offs, int whence, void *uptr)
   7.155 +{
   7.156 +	return ass_fseek(uptr, offs, whence);
   7.157 +}
   7.158 +
   7.159 +static unsigned int next_pow2(unsigned int x)
   7.160 +{
   7.161 +	x--;
   7.162 +	x = (x >> 1) | x;
   7.163 +	x = (x >> 2) | x;
   7.164 +	x = (x >> 4) | x;
   7.165 +	x = (x >> 8) | x;
   7.166 +	x = (x >> 16) | x;
   7.167 +	return x + 1;
   7.168 +}
     8.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     8.2 +++ b/src/texture.h	Wed Jun 10 06:56:27 2015 +0300
     8.3 @@ -0,0 +1,15 @@
     8.4 +#ifndef TEXTURE_H_
     8.5 +#define TEXTURE_H_
     8.6 +
     8.7 +struct texture {
     8.8 +	unsigned int texid;
     8.9 +	int width, height;
    8.10 +	int img_width, img_height;	/* in case we have a smaller image in a pow2 texture */
    8.11 +};
    8.12 +
    8.13 +int load_texture(struct texture *tex, const char *fname);
    8.14 +struct texture *get_texture(const char *fname);
    8.15 +
    8.16 +int gen_debug_texture(struct texture *tex);
    8.17 +
    8.18 +#endif	/* TEXTURE_H_ */