# HG changeset patch # User John Tsiombikas # Date 1433908587 -10800 # Node ID aef7f51f639709f69724b60c7fd3fcce701f37bc # Parent c6952cc82ccaeb072ac7c8305b7cbd2f4d958778 resource loading works diff -r c6952cc82cca -r aef7f51f6397 src/android/assman.c --- a/src/android/assman.c Tue Jun 09 18:38:33 2015 +0300 +++ b/src/android/assman.c Wed Jun 10 06:56:27 2015 +0300 @@ -4,11 +4,39 @@ #include "native_glue.h" #include "amain.h" -ass_file *ass_fopen(const char *fname) +ass_file *ass_fopen(const char *fname, const char *mode) { AAsset *ass; + unsigned int flags = 0; + char prev = 0; - if(!(ass = AAssetManager_open(app->activity->assetManager, fname, O_RDONLY))) { + while(*mode) { + switch(*mode) { + case 'r': + flags |= O_RDONLY; + break; + + case 'w': + flags |= O_WRONLY; + break; + + case 'a': + flags |= O_APPEND; + break; + + case '+': + if(prev == 'w' || prev == 'a') { + flags |= O_CREAT; + } + break; + + default: + break; + } + prev = *mode++; + } + + if(!(ass = AAssetManager_open(app->activity->assetManager, fname, flags))) { return 0; } return (ass_file*)ass; diff -r c6952cc82cca -r aef7f51f6397 src/assman.h --- a/src/assman.h Tue Jun 09 18:38:33 2015 +0300 +++ b/src/assman.h Wed Jun 10 06:56:27 2015 +0300 @@ -5,7 +5,7 @@ typedef void ass_file; -ass_file *ass_fopen(const char *fname); +ass_file *ass_fopen(const char *fname, const char *mode); void ass_fclose(ass_file *fp); long ass_fseek(ass_file *fp, long offs, int whence); diff -r c6952cc82cca -r aef7f51f6397 src/game.c --- a/src/game.c Tue Jun 09 18:38:33 2015 +0300 +++ b/src/game.c Wed Jun 10 06:56:27 2015 +0300 @@ -7,15 +7,19 @@ #include "camera.h" #include "sdr.h" #include "sanegl.h" +#include "texture.h" -static void draw_quad(float hsz, float vsz); +static void draw_quad(float hsz, float vsz, unsigned int sdr); static int win_width, win_height; static float win_aspect; static int video_width, video_height; static float video_aspect; -static unsigned int sdrprog; -static int aloc_vertex, aloc_texcoord, uloc_tex; +static unsigned int sdrprog, sdrprog_test; +static int uloc_tex, uloc_test_tex; +static struct texture *test_tex; + +enum { ATTR_VERTEX, ATTR_TEXCOORD }; static const char *vsdr_source = "attribute vec4 attr_vertex, attr_texcoord;\n" @@ -28,7 +32,7 @@ "\ttex_coords = matrix_texture * attr_texcoord;\n" "}\n"; -static const char *psdr_source = +static const char *psdr_cam_source = "#extension GL_OES_EGL_image_external : require\n" "precision mediump float;\n" "uniform samplerExternalOES tex;\n" @@ -39,12 +43,21 @@ "\tgl_FragColor = vec4(texel.xyz, 1.0);\n" "}\n"; +static const char *psdr_tex_source = + "precision mediump float;\n" + "uniform sampler2D tex;\n" + "varying vec4 tex_coords;\n" + "void main()\n" + "{\n" + "\tvec4 texel = texture2D(tex, tex_coords.xy);\n" + "\tgl_FragColor = texel;\n" + "}\n"; int game_init(void) { - unsigned int vsdr, psdr; + unsigned int vsdr, psdr_cam, psdr_tex; - glEnable(GL_DEPTH_TEST); + //glEnable(GL_DEPTH_TEST); glEnable(GL_CULL_FACE); glClearColor(0.4, 0.4, 0.4, 1); @@ -52,17 +65,36 @@ if(!(vsdr = create_vertex_shader(vsdr_source))) return -1; assert(glGetError() == GL_NO_ERROR); - if(!(psdr = create_pixel_shader(psdr_source))) + if(!(psdr_cam = create_pixel_shader(psdr_cam_source))) return -1; assert(glGetError() == GL_NO_ERROR); - if(!(sdrprog = create_program_link(vsdr, psdr))) { + if(!(psdr_tex = create_pixel_shader(psdr_tex_source))) + return -1; + assert(glGetError() == GL_NO_ERROR); + if(!(sdrprog = create_program_link(vsdr, psdr_cam, 0))) { fprintf(stderr, "failed to create shader program\n"); return -1; } + if(!(sdrprog_test = create_program_link(vsdr, psdr_tex, 0))) { + fprintf(stderr, "failed to create test shader program\n"); + return -1; + } + glUseProgram(sdrprog); - aloc_vertex = glGetAttribLocation(sdrprog, "attr_vertex"); - aloc_texcoord = glGetAttribLocation(sdrprog, "attr_texcoord"); + glBindAttribLocation(sdrprog, ATTR_VERTEX, "attr_vertex"); + glBindAttribLocation(sdrprog, ATTR_TEXCOORD, "attr_texcoord"); uloc_tex = glGetUniformLocation(sdrprog, "tex"); + glLinkProgram(sdrprog); + + glUseProgram(sdrprog_test); + glBindAttribLocation(sdrprog_test, ATTR_VERTEX, "attr_vertex"); + glBindAttribLocation(sdrprog_test, ATTR_TEXCOORD, "attr_texcoord"); + uloc_test_tex = glGetUniformLocation(sdrprog_test, "tex"); + glLinkProgram(sdrprog_test); + + if(!(test_tex = get_texture("data/opengl.png"))) { + return -1; + } cam_start_video(); cam_video_size(&video_width, &video_height); @@ -94,7 +126,6 @@ //float tsec = (float)msec / 1000.0f; - //glClearColor(sin(tsec * 10.0), cos(tsec * 10.0), -sin(tsec * 10.0), 1.0); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); gl_matrix_mode(GL_MODELVIEW); @@ -115,37 +146,50 @@ xscale = video_aspect; yscale = 1.0; } - draw_quad(xscale, yscale); + draw_quad(xscale, yscale, sdrprog); + + gl_matrix_mode(GL_TEXTURE); + gl_load_identity(); + gl_translatef(0, 1, 0); + gl_scalef(1, -1, 1); + gl_matrix_mode(GL_MODELVIEW); + gl_load_identity(); + gl_scalef((float)test_tex->width / (float)test_tex->height, 1, 1); + + glUseProgram(sdrprog_test); + glBindTexture(GL_TEXTURE_2D, test_tex->texid); + if(uloc_test_tex >= 0) { + glUniform1i(uloc_test_tex, 0); + } + + glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + + draw_quad(0.5, 0.5, sdrprog_test); + + glDisable(GL_BLEND); } -static void draw_quad(float hsz, float vsz) +static void draw_quad(float hsz, float vsz, unsigned int sdr) { static const float varr[] = {-1, -1, 1, -1, 1, 1, -1, 1}; static const float tcarr[] = {0, 0, 1, 0, 1, 1, 0, 1}; - if(aloc_vertex == -1) { - return; - } - gl_matrix_mode(GL_MODELVIEW); gl_push_matrix(); gl_scalef(hsz, vsz, 1); - gl_apply_xform(sdrprog); + gl_apply_xform(sdr); - glEnableVertexAttribArray(aloc_vertex); - glVertexAttribPointer(aloc_vertex, 2, GL_FLOAT, 0, 0, varr); - if(aloc_texcoord != -1) { - glEnableVertexAttribArray(aloc_texcoord); - glVertexAttribPointer(aloc_texcoord, 2, GL_FLOAT, 0, 0, tcarr); - } + glEnableVertexAttribArray(ATTR_VERTEX); + glEnableVertexAttribArray(ATTR_TEXCOORD); + glVertexAttribPointer(ATTR_VERTEX, 2, GL_FLOAT, 0, 0, varr); + glVertexAttribPointer(ATTR_TEXCOORD, 2, GL_FLOAT, 0, 0, tcarr); glDrawArrays(GL_TRIANGLE_FAN, 0, 4); - glDisableVertexAttribArray(aloc_vertex); - if(aloc_texcoord != -1) { - glDisableVertexAttribArray(aloc_texcoord); - } + glDisableVertexAttribArray(ATTR_VERTEX); + glDisableVertexAttribArray(ATTR_TEXCOORD); gl_pop_matrix(); } diff -r c6952cc82cca -r aef7f51f6397 src/rbtree.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/rbtree.c Wed Jun 10 06:56:27 2015 +0300 @@ -0,0 +1,501 @@ +/* +rbtree - simple balanced binary search tree (red-black tree) library. +Copyright (C) 2011-2014 John Tsiombikas + +rbtree is free software, feel free to use, modify, and redistribute it, under +the terms of the 3-clause BSD license. See COPYING for details. + */ +#include +#include +#include +#include +#include "rbtree.h" + +#define INT2PTR(x) ((void*)(intptr_t)(x)) +#define PTR2INT(x) ((int)(intptr_t)(x)) + +struct rbtree { + struct rbnode *root; + + rb_alloc_func_t alloc; + rb_free_func_t free; + + rb_cmp_func_t cmp; + rb_del_func_t del; + void *del_cls; + + struct rbnode *rstack, *iter; +}; + +static int cmpaddr(const void *ap, const void *bp); +static int cmpint(const void *ap, const void *bp); + +static int count_nodes(struct rbnode *node); +static void del_tree(struct rbnode *node, void (*delfunc)(struct rbnode*, void*), void *cls); +static struct rbnode *insert(struct rbtree *rb, struct rbnode *tree, void *key, void *data); +static struct rbnode *delete(struct rbtree *rb, struct rbnode *tree, void *key); +/*static struct rbnode *find(struct rbtree *rb, struct rbnode *node, void *key);*/ +static void traverse(struct rbnode *node, void (*func)(struct rbnode*, void*), void *cls); + +struct rbtree *rb_create(rb_cmp_func_t cmp_func) +{ + struct rbtree *rb; + + if(!(rb = malloc(sizeof *rb))) { + return 0; + } + if(rb_init(rb, cmp_func) == -1) { + free(rb); + return 0; + } + return rb; +} + +void rb_free(struct rbtree *rb) +{ + rb_destroy(rb); + free(rb); +} + + +int rb_init(struct rbtree *rb, rb_cmp_func_t cmp_func) +{ + memset(rb, 0, sizeof *rb); + + if(!cmp_func) { + rb->cmp = cmpaddr; + } else if(cmp_func == RB_KEY_INT) { + rb->cmp = cmpint; + } else if(cmp_func == RB_KEY_STRING) { + rb->cmp = (rb_cmp_func_t)strcmp; + } else { + rb->cmp = cmp_func; + } + + rb->alloc = malloc; + rb->free = free; + return 0; +} + +void rb_destroy(struct rbtree *rb) +{ + del_tree(rb->root, rb->del, rb->del_cls); +} + +void rb_set_allocator(struct rbtree *rb, rb_alloc_func_t alloc, rb_free_func_t free) +{ + rb->alloc = alloc; + rb->free = free; +} + + +void rb_set_compare_func(struct rbtree *rb, rb_cmp_func_t func) +{ + rb->cmp = func; +} + +void rb_set_delete_func(struct rbtree *rb, rb_del_func_t func, void *cls) +{ + rb->del = func; + rb->del_cls = cls; +} + + +void rb_clear(struct rbtree *rb) +{ + del_tree(rb->root, rb->del, rb->del_cls); + rb->root = 0; +} + +int rb_copy(struct rbtree *dest, struct rbtree *src) +{ + struct rbnode *node; + + rb_clear(dest); + rb_begin(src); + while((node = rb_next(src))) { + if(rb_insert(dest, node->key, node->data) == -1) { + return -1; + } + } + return 0; +} + +int rb_size(struct rbtree *rb) +{ + return count_nodes(rb->root); +} + +int rb_insert(struct rbtree *rb, void *key, void *data) +{ + rb->root = insert(rb, rb->root, key, data); + rb->root->red = 0; + return 0; +} + +int rb_inserti(struct rbtree *rb, int key, void *data) +{ + rb->root = insert(rb, rb->root, INT2PTR(key), data); + rb->root->red = 0; + return 0; +} + + +int rb_delete(struct rbtree *rb, void *key) +{ + rb->root = delete(rb, rb->root, key); + rb->root->red = 0; + return 0; +} + +int rb_deletei(struct rbtree *rb, int key) +{ + rb->root = delete(rb, rb->root, INT2PTR(key)); + rb->root->red = 0; + return 0; +} + + +struct rbnode *rb_find(struct rbtree *rb, void *key) +{ + struct rbnode *node = rb->root; + + while(node) { + int cmp = rb->cmp(key, node->key); + if(cmp == 0) { + return node; + } + node = cmp < 0 ? node->left : node->right; + } + return 0; +} + +struct rbnode *rb_findi(struct rbtree *rb, int key) +{ + return rb_find(rb, INT2PTR(key)); +} + + +void rb_foreach(struct rbtree *rb, void (*func)(struct rbnode*, void*), void *cls) +{ + traverse(rb->root, func, cls); +} + + +struct rbnode *rb_root(struct rbtree *rb) +{ + return rb->root; +} + +void rb_begin(struct rbtree *rb) +{ + rb->rstack = 0; + rb->iter = rb->root; +} + +#define push(sp, x) ((x)->next = (sp), (sp) = (x)) +#define pop(sp) ((sp) = (sp)->next) +#define top(sp) (sp) + +struct rbnode *rb_next(struct rbtree *rb) +{ + struct rbnode *res = 0; + + while(rb->rstack || rb->iter) { + if(rb->iter) { + push(rb->rstack, rb->iter); + rb->iter = rb->iter->left; + } else { + rb->iter = top(rb->rstack); + pop(rb->rstack); + res = rb->iter; + rb->iter = rb->iter->right; + break; + } + } + return res; +} + +void *rb_node_key(struct rbnode *node) +{ + return node ? node->key : 0; +} + +int rb_node_keyi(struct rbnode *node) +{ + return node ? PTR2INT(node->key) : 0; +} + +void *rb_node_data(struct rbnode *node) +{ + return node ? node->data : 0; +} + +static int cmpaddr(const void *ap, const void *bp) +{ + return ap < bp ? -1 : (ap > bp ? 1 : 0); +} + +static int cmpint(const void *ap, const void *bp) +{ + return PTR2INT(ap) - PTR2INT(bp); +} + + +/* ---- left-leaning 2-3 red-black implementation ---- */ + +/* helper prototypes */ +static int is_red(struct rbnode *tree); +static void color_flip(struct rbnode *tree); +static struct rbnode *rot_left(struct rbnode *a); +static struct rbnode *rot_right(struct rbnode *a); +static struct rbnode *find_min(struct rbnode *tree); +static struct rbnode *del_min(struct rbtree *rb, struct rbnode *tree); +/*static struct rbnode *move_red_right(struct rbnode *tree);*/ +static struct rbnode *move_red_left(struct rbnode *tree); +static struct rbnode *fix_up(struct rbnode *tree); + +static int count_nodes(struct rbnode *node) +{ + if(!node) + return 0; + + return 1 + count_nodes(node->left) + count_nodes(node->right); +} + +static void del_tree(struct rbnode *node, rb_del_func_t delfunc, void *cls) +{ + if(!node) + return; + + del_tree(node->left, delfunc, cls); + del_tree(node->right, delfunc, cls); + + if(delfunc) { + delfunc(node, cls); + } + free(node); +} + +static struct rbnode *insert(struct rbtree *rb, struct rbnode *tree, void *key, void *data) +{ + int cmp; + + if(!tree) { + struct rbnode *node = rb->alloc(sizeof *node); + node->red = 1; + node->key = key; + node->data = data; + node->left = node->right = 0; + return node; + } + + cmp = rb->cmp(key, tree->key); + + if(cmp < 0) { + tree->left = insert(rb, tree->left, key, data); + } else if(cmp > 0) { + tree->right = insert(rb, tree->right, key, data); + } else { + tree->data = data; + } + + /* fix right-leaning reds */ + if(is_red(tree->right)) { + tree = rot_left(tree); + } + /* fix two reds in a row */ + if(is_red(tree->left) && is_red(tree->left->left)) { + tree = rot_right(tree); + } + + /* if 4-node, split it by color inversion */ + if(is_red(tree->left) && is_red(tree->right)) { + color_flip(tree); + } + + return tree; +} + +static struct rbnode *delete(struct rbtree *rb, struct rbnode *tree, void *key) +{ + int cmp; + + if(!tree) { + return 0; + } + + cmp = rb->cmp(key, tree->key); + + if(cmp < 0) { + if(!is_red(tree->left) && !is_red(tree->left->left)) { + tree = move_red_left(tree); + } + tree->left = delete(rb, tree->left, key); + } else { + /* need reds on the right */ + if(is_red(tree->left)) { + tree = rot_right(tree); + } + + /* found it at the bottom (XXX what certifies left is null?) */ + if(cmp == 0 && !tree->right) { + if(rb->del) { + rb->del(tree, rb->del_cls); + } + rb->free(tree); + return 0; + } + + if(!is_red(tree->right) && !is_red(tree->right->left)) { + tree = move_red_left(tree); + } + + if(key == tree->key) { + struct rbnode *rmin = find_min(tree->right); + tree->key = rmin->key; + tree->data = rmin->data; + tree->right = del_min(rb, tree->right); + } else { + tree->right = delete(rb, tree->right, key); + } + } + + return fix_up(tree); +} + +/*static struct rbnode *find(struct rbtree *rb, struct rbnode *node, void *key) +{ + int cmp; + + if(!node) + return 0; + + if((cmp = rb->cmp(key, node->key)) == 0) { + return node; + } + return find(rb, cmp < 0 ? node->left : node->right, key); +}*/ + +static void traverse(struct rbnode *node, void (*func)(struct rbnode*, void*), void *cls) +{ + if(!node) + return; + + traverse(node->left, func, cls); + func(node, cls); + traverse(node->right, func, cls); +} + +/* helpers */ + +static int is_red(struct rbnode *tree) +{ + return tree && tree->red; +} + +static void color_flip(struct rbnode *tree) +{ + tree->red = !tree->red; + tree->left->red = !tree->left->red; + tree->right->red = !tree->right->red; +} + +static struct rbnode *rot_left(struct rbnode *a) +{ + struct rbnode *b = a->right; + a->right = b->left; + b->left = a; + b->red = a->red; + a->red = 1; + return b; +} + +static struct rbnode *rot_right(struct rbnode *a) +{ + struct rbnode *b = a->left; + a->left = b->right; + b->right = a; + b->red = a->red; + a->red = 1; + return b; +} + +static struct rbnode *find_min(struct rbnode *tree) +{ + if(!tree) + return 0; + + while(tree->left) { + tree = tree->left; + } + return tree; +} + +static struct rbnode *del_min(struct rbtree *rb, struct rbnode *tree) +{ + if(!tree->left) { + if(rb->del) { + rb->del(tree->left, rb->del_cls); + } + rb->free(tree->left); + return 0; + } + + /* make sure we've got red (3/4-nodes) at the left side so we can delete at the bottom */ + if(!is_red(tree->left) && !is_red(tree->left->left)) { + tree = move_red_left(tree); + } + tree->left = del_min(rb, tree->left); + + /* fix right-reds, red-reds, and split 4-nodes on the way up */ + return fix_up(tree); +} + +#if 0 +/* push a red link on this node to the right */ +static struct rbnode *move_red_right(struct rbnode *tree) +{ + /* flipping it makes both children go red, so we have a red to the right */ + color_flip(tree); + + /* if after the flip we've got a red-red situation to the left, fix it */ + if(is_red(tree->left->left)) { + tree = rot_right(tree); + color_flip(tree); + } + return tree; +} +#endif + +/* push a red link on this node to the left */ +static struct rbnode *move_red_left(struct rbnode *tree) +{ + /* flipping it makes both children go red, so we have a red to the left */ + color_flip(tree); + + /* if after the flip we've got a red-red on the right-left, fix it */ + if(is_red(tree->right->left)) { + tree->right = rot_right(tree->right); + tree = rot_left(tree); + color_flip(tree); + } + return tree; +} + +static struct rbnode *fix_up(struct rbnode *tree) +{ + /* fix right-leaning */ + if(is_red(tree->right)) { + tree = rot_left(tree); + } + /* change invalid red-red pairs into a proper 4-node */ + if(is_red(tree->left) && is_red(tree->left->left)) { + tree = rot_right(tree); + } + /* split 4-nodes */ + if(is_red(tree->left) && is_red(tree->right)) { + color_flip(tree); + } + return tree; +} diff -r c6952cc82cca -r aef7f51f6397 src/rbtree.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/rbtree.h Wed Jun 10 06:56:27 2015 +0300 @@ -0,0 +1,78 @@ +/* +rbtree - simple balanced binary search tree (red-black tree) library. +Copyright (C) 2011-2014 John Tsiombikas + +rbtree is free software, feel free to use, modify, and redistribute it, under +the terms of the 3-clause BSD license. See COPYING for details. + */ +#ifndef RBTREE_H_ +#define RBTREE_H_ + +struct rbtree; + + +struct rbnode { + void *key, *data; + int red; + struct rbnode *left, *right; + struct rbnode *next; /* for iterator stack */ +}; + + +typedef void *(*rb_alloc_func_t)(size_t); +typedef void (*rb_free_func_t)(void*); + +typedef int (*rb_cmp_func_t)(const void*, const void*); +typedef void (*rb_del_func_t)(struct rbnode*, void*); + +#define RB_KEY_ADDR (rb_cmp_func_t)(0) +#define RB_KEY_INT (rb_cmp_func_t)(1) +#define RB_KEY_STRING (rb_cmp_func_t)(3) + + +#ifdef __cplusplus +extern "C" { +#endif + +struct rbtree *rb_create(rb_cmp_func_t cmp_func); +void rb_free(struct rbtree *rb); + +int rb_init(struct rbtree *rb, rb_cmp_func_t cmp_func); +void rb_destroy(struct rbtree *rb); + +void rb_set_allocator(struct rbtree *rb, rb_alloc_func_t alloc, rb_free_func_t free); +void rb_set_compare_func(struct rbtree *rb, rb_cmp_func_t func); +void rb_set_delete_func(struct rbtree *rb, rb_del_func_t func, void *cls); +/* TODO add user deep copy function */ + +void rb_clear(struct rbtree *rb); +int rb_copy(struct rbtree *dest, struct rbtree *src); + +int rb_size(struct rbtree *rb); + +int rb_insert(struct rbtree *rb, void *key, void *data); +int rb_inserti(struct rbtree *rb, int key, void *data); + +int rb_delete(struct rbtree *rb, void *key); +int rb_deletei(struct rbtree *rb, int key); + +struct rbnode *rb_find(struct rbtree *rb, void *key); +struct rbnode *rb_findi(struct rbtree *rb, int key); + +void rb_foreach(struct rbtree *rb, void (*func)(struct rbnode*, void*), void *cls); + +struct rbnode *rb_root(struct rbtree *rb); + +void rb_begin(struct rbtree *rb); +struct rbnode *rb_next(struct rbtree *rb); + +void *rb_node_key(struct rbnode *node); +int rb_node_keyi(struct rbnode *node); +void *rb_node_data(struct rbnode *node); + +#ifdef __cplusplus +} +#endif + + +#endif /* RBTREE_H_ */ diff -r c6952cc82cca -r aef7f51f6397 src/sdr.c --- a/src/sdr.c Tue Jun 09 18:38:33 2015 +0300 +++ b/src/sdr.c Wed Jun 10 06:56:27 2015 +0300 @@ -233,10 +233,13 @@ void attach_shader(unsigned int prog, unsigned int sdr) { + int err; + if(prog && sdr) { + assert(glGetError() == GL_NO_ERROR); glAttachShader(prog, sdr); - if(glGetError() != GL_NO_ERROR) { - fprintf(stderr, "failed to attach shader %u to program %u\n", sdr, prog); + if((err = glGetError()) != GL_NO_ERROR) { + fprintf(stderr, "failed to attach shader %u to program %u (err: 0x%x)\n", sdr, prog, err); abort(); } } diff -r c6952cc82cca -r aef7f51f6397 src/texture.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/texture.c Wed Jun 10 06:56:27 2015 +0300 @@ -0,0 +1,165 @@ +#include +#include +#include +#include +#include +#include "opengl.h" +#include "texture.h" +#include "imago2.h" +#include "rbtree.h" +#include "assman.h" + +static size_t ioread(void *buf, size_t bytes, void *uptr); +static long ioseek(long offs, int whence, void *uptr); +static unsigned int next_pow2(unsigned int x); + +static struct rbtree *texdb; + +int load_texture(struct texture *tex, const char *fname) +{ + struct img_pixmap img; + struct img_io io; + ass_file *fp; + + printf("loading texture: %s\n", fname); + + if(!(fp = ass_fopen(fname, "rb"))) { + fprintf(stderr, "failed to open texture file: %s: %s\n", fname, strerror(errno)); + return -1; + } + io.uptr = fp; + io.read = ioread; + io.write = 0; + io.seek = ioseek; + + img_init(&img); + if(img_read(&img, &io) == -1) { + fprintf(stderr, "failed to load texture file: %s\n", fname); + ass_fclose(fp); + return -1; + } + img_convert(&img, IMG_FMT_RGBA32); + + tex->img_width = img.width; + tex->img_height = img.height; + tex->width = next_pow2(img.width); + tex->height = next_pow2(img.height); + + printf(" %dx%d (tex: %dx%d)\n", tex->img_width, tex->img_height, tex->width, tex->height); + + glGenTextures(1, &tex->texid); + glBindTexture(GL_TEXTURE_2D, tex->texid); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + +#ifdef __GLEW_H__ + if(GLEW_SGIS_generate_mipmap) { + glTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP_SGIS, GL_TRUE); +#endif + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, tex->width, tex->height, 0, + GL_RGBA, GL_UNSIGNED_BYTE, img.pixels); +#ifdef __GLEW_H__ + } else { + gluBuild2DMipmaps(GL_TEXTURE_2D, GL_RGBA, tex->width, tex->height, + GL_RGBA, GL_UNSIGNED_BYTE, img.pixels); + } +#endif + +#ifdef GL_ES_VERSION_2_0 + glGenerateMipmap(GL_TEXTURE_2D); +#endif + + return 0; +} + +struct texture *get_texture(const char *fname) +{ + struct texture *tex; + struct rbnode *node; + + if(!(texdb = rb_create(RB_KEY_STRING))) { + static int err_printed; + if(!err_printed) { + fprintf(stderr, "failed to create texture database\n"); + err_printed = 1; + } + return 0; + } + + if((node = rb_find(texdb, (void*)fname))) { + return rb_node_data(node); + } + + if(!(tex = malloc(sizeof *tex))) { + fprintf(stderr, "failed to load texture \"%s\": %s\n", fname, strerror(errno)); + return 0; + } + if(load_texture(tex, fname) == -1) { + free(tex); + return 0; + } + + if(rb_insert(texdb, (void*)fname, tex) == -1) { + fprintf(stderr, "failed to insert texture into the texture database\n"); + } + return tex; +} + + +#define DBG_TEX_SZ 64 +int gen_debug_texture(struct texture *tex) +{ + static unsigned char *pixels; + + if(!pixels) { + int i, j; + unsigned char *pptr; + pptr = pixels = malloc(DBG_TEX_SZ * DBG_TEX_SZ * 4); + assert(pixels); + + for(i=0; i> 3) & 1) == ((i >> 3) & 1); + *pptr++ = chess ? 255 : 64; + *pptr++ = 128; + *pptr++ = chess ? 64 : 255; + *pptr++ = 255; /* alpha */ + } + } + } + + if(!tex->texid) { + glGenTextures(1, &tex->texid); + } + + glBindTexture(GL_TEXTURE_2D, tex->texid); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, DBG_TEX_SZ, DBG_TEX_SZ, 0, GL_RGBA, + GL_UNSIGNED_BYTE, pixels); + + tex->width = tex->img_width = tex->height = tex->img_height = DBG_TEX_SZ; + return 0; +} + + +static size_t ioread(void *buf, size_t bytes, void *uptr) +{ + return ass_fread(buf, 1, bytes, uptr); +} + +static long ioseek(long offs, int whence, void *uptr) +{ + return ass_fseek(uptr, offs, whence); +} + +static unsigned int next_pow2(unsigned int x) +{ + x--; + x = (x >> 1) | x; + x = (x >> 2) | x; + x = (x >> 4) | x; + x = (x >> 8) | x; + x = (x >> 16) | x; + return x + 1; +} diff -r c6952cc82cca -r aef7f51f6397 src/texture.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/texture.h Wed Jun 10 06:56:27 2015 +0300 @@ -0,0 +1,15 @@ +#ifndef TEXTURE_H_ +#define TEXTURE_H_ + +struct texture { + unsigned int texid; + int width, height; + int img_width, img_height; /* in case we have a smaller image in a pow2 texture */ +}; + +int load_texture(struct texture *tex, const char *fname); +struct texture *get_texture(const char *fname); + +int gen_debug_texture(struct texture *tex); + +#endif /* TEXTURE_H_ */