scenefile

changeset 3:b30f83409769

foo
author John Tsiombikas <nuclear@mutantstargoat.com>
date Sat, 21 Jan 2012 04:14:24 +0200
parents c15992cedec9
children d251485d33d8
files scnviewgl/scnviewgl.c src/file_milk.c src/mesh.c src/mesh.h src/scene.c src/scene.h
diffstat 6 files changed, 473 insertions(+), 7 deletions(-) [+]
line diff
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/scnviewgl/scnviewgl.c	Sat Jan 21 04:14:24 2012 +0200
     1.3 @@ -0,0 +1,262 @@
     1.4 +#include <stdio.h>
     1.5 +#include <assert.h>
     1.6 +
     1.7 +#ifndef __APPLE__
     1.8 +#include <GL/glut.h>
     1.9 +#else
    1.10 +#include <GLUT/glut.h>
    1.11 +#endif
    1.12 +
    1.13 +#include "scene.h"
    1.14 +
    1.15 +void disp(void);
    1.16 +void render_scene(struct scenefile *scn);
    1.17 +void render_mesh(struct mesh *m);
    1.18 +void reshape(int x, int y);
    1.19 +void keyb(unsigned char key, int x, int y);
    1.20 +void mouse(int bn, int state, int x, int y);
    1.21 +void motion(int x, int y);
    1.22 +void sball_motion(int x, int y, int z);
    1.23 +void sball_rotate(int x, int y, int z);
    1.24 +void sball_button(int bn, int state);
    1.25 +int parse_args(int argc, char **argv);
    1.26 +
    1.27 +struct scenefile *scn;
    1.28 +float cam_theta, cam_phi, cam_dist = 10;
    1.29 +
    1.30 +int main(int argc, char **argv)
    1.31 +{
    1.32 +	float ldir[] = {-1, 1, 1, 0};
    1.33 +
    1.34 +	glutInitWindowSize(800, 600);
    1.35 +	glutInit(&argc, argv);
    1.36 +
    1.37 +	if(parse_args(argc, argv) == -1) {
    1.38 +		return 1;
    1.39 +	}
    1.40 +
    1.41 +	glutInitDisplayMode(GLUT_RGB | GLUT_DEPTH | GLUT_DOUBLE);
    1.42 +	glutCreateWindow("OpenGL Scene Viewer");
    1.43 +
    1.44 +	glutDisplayFunc(disp);
    1.45 +	glutReshapeFunc(reshape);
    1.46 +	glutKeyboardFunc(keyb);
    1.47 +	glutMouseFunc(mouse);
    1.48 +	glutMotionFunc(motion);
    1.49 +	glutSpaceballMotionFunc(sball_motion);
    1.50 +	glutSpaceballRotateFunc(sball_rotate);
    1.51 +	glutSpaceballButtonFunc(sball_button);
    1.52 +
    1.53 +	glEnable(GL_DEPTH_TEST);
    1.54 +	glEnable(GL_CULL_FACE);
    1.55 +	glEnable(GL_LIGHTING);
    1.56 +	glEnable(GL_LIGHT0);
    1.57 +	glLightfv(GL_LIGHT0, GL_POSITION, ldir);
    1.58 +
    1.59 +	glutMainLoop();
    1.60 +	return 0;
    1.61 +}
    1.62 +
    1.63 +
    1.64 +void disp(void)
    1.65 +{
    1.66 +	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    1.67 +
    1.68 +	glMatrixMode(GL_MODELVIEW);
    1.69 +	glLoadIdentity();
    1.70 +	glRotatef(cam_theta, 0, 1, 0);
    1.71 +	glRotatef(cam_phi, 1, 0, 0);
    1.72 +	glTranslatef(0, 0, -cam_dist);
    1.73 +
    1.74 +	render_scene(scn);
    1.75 +
    1.76 +	glutSwapBuffers();
    1.77 +}
    1.78 +
    1.79 +void render_scene(struct scenefile *scn)
    1.80 +{
    1.81 +	int i, num = scnfile_count(scn);
    1.82 +
    1.83 +	for(i=0; i<num; i++) {
    1.84 +		struct mesh *m = scnfile_mesh(scn, i);
    1.85 +		render_mesh(m);
    1.86 +	}
    1.87 +}
    1.88 +
    1.89 +void render_mesh(struct mesh *m)
    1.90 +{
    1.91 +	int i, j, poly_verts, npoly;
    1.92 +	int vloc, nloc, tloc;
    1.93 +	int *vidx, *nidx, *tidx;
    1.94 +
    1.95 +	npoly = mesh_poly_count(m);
    1.96 +	poly_verts = mesh_poly_type(m);
    1.97 +
    1.98 +	if((vloc = mesh_find_attrib(m, "vertex")) == -1) {
    1.99 +		return;
   1.100 +	}
   1.101 +	vidx = mesh_poly_data(m, vloc);
   1.102 +
   1.103 +	if((nloc = mesh_find_attrib(m, "normal")) != -1) {
   1.104 +		nidx = mesh_poly_data(m, nloc);
   1.105 +	}
   1.106 +
   1.107 +	if((tloc = mesh_find_attrib(m, "texture")) != -1) {
   1.108 +		tidx = mesh_poly_data(m, tloc);
   1.109 +	}
   1.110 +
   1.111 +	glBegin(poly_verts == 3 ? GL_TRIANGLES : GL_QUADS);
   1.112 +	for(i=0; i<npoly; i++) {
   1.113 +		for(j=0; j<poly_verts; j++) {
   1.114 +			void *ptr;
   1.115 +			if(nloc >= 0) {
   1.116 +				ptr = mesh_attrib_elem(m, nloc, *nidx++);
   1.117 +				assert(ptr);
   1.118 +				glNormal3fv(ptr);
   1.119 +			}
   1.120 +			if(tloc >= 0) {
   1.121 +				ptr = mesh_attrib_elem(m, tloc, *tidx++);
   1.122 +				assert(ptr);
   1.123 +				glTexCoord2fv(ptr);
   1.124 +			}
   1.125 +			ptr = mesh_attrib_elem(m, vloc, *vidx++);
   1.126 +			assert(ptr);
   1.127 +			glVertex3fv(ptr);
   1.128 +		}
   1.129 +	}
   1.130 +	glEnd();
   1.131 +}
   1.132 +
   1.133 +
   1.134 +void reshape(int x, int y)
   1.135 +{
   1.136 +	glViewport(0, 0, x, y);
   1.137 +
   1.138 +	glMatrixMode(GL_PROJECTION);
   1.139 +	glLoadIdentity();
   1.140 +	gluPerspective(45.0, (float)x / (float)y, 0.5, 1000.0);
   1.141 +}
   1.142 +
   1.143 +void keyb(unsigned char key, int x, int y)
   1.144 +{
   1.145 +	switch(key) {
   1.146 +	case 27:
   1.147 +	case 'q':
   1.148 +		exit(0);
   1.149 +
   1.150 +	case 'c':
   1.151 +		{
   1.152 +			static int flip;
   1.153 +			if(++flip & 1) {
   1.154 +				glFrontFace(GL_CW);
   1.155 +			} else {
   1.156 +				glFrontFace(GL_CCW);
   1.157 +			}
   1.158 +		}
   1.159 +		break;
   1.160 +
   1.161 +	case 'l':
   1.162 +		{
   1.163 +			static int lton = 1;
   1.164 +			if(++lton & 1) {
   1.165 +				glEnable(GL_LIGHTING);
   1.166 +			} else {
   1.167 +				glDisable(GL_LIGHTING);
   1.168 +			}
   1.169 +		}
   1.170 +		break;
   1.171 +
   1.172 +	case 'w':
   1.173 +		{
   1.174 +			static int wire;
   1.175 +			if(++wire & 1) {
   1.176 +				glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
   1.177 +			} else {
   1.178 +				glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
   1.179 +			}
   1.180 +		}
   1.181 +		break;
   1.182 +
   1.183 +	default:
   1.184 +		break;
   1.185 +	}
   1.186 +}
   1.187 +
   1.188 +int prev_x, prev_y;
   1.189 +int bnstate[32];
   1.190 +
   1.191 +void mouse(int bn, int state, int x, int y)
   1.192 +{
   1.193 +	bnstate[bn] = state == GLUT_DOWN ? 1 : 0;
   1.194 +	prev_x = x;
   1.195 +	prev_y = y;
   1.196 +}
   1.197 +
   1.198 +void motion(int x, int y)
   1.199 +{
   1.200 +	int dx = x - prev_x;
   1.201 +	int dy = y - prev_y;
   1.202 +	prev_x = x;
   1.203 +	prev_y = y;
   1.204 +
   1.205 +	if(bnstate[1]) {
   1.206 +		cam_theta += (float)dx;
   1.207 +		cam_phi += (float)dy;
   1.208 +
   1.209 +		if(cam_phi < -90)
   1.210 +			cam_phi = -90;
   1.211 +		if(cam_phi > 90)
   1.212 +			cam_phi = 90;
   1.213 +	}
   1.214 +	if(bnstate[3]) {
   1.215 +		cam_dist += (float)dy * 0.1;
   1.216 +
   1.217 +		if(cam_dist < 0)
   1.218 +			cam_dist = 0;
   1.219 +	}
   1.220 +}
   1.221 +
   1.222 +void sball_motion(int x, int y, int z)
   1.223 +{
   1.224 +}
   1.225 +
   1.226 +void sball_rotate(int x, int y, int z)
   1.227 +{
   1.228 +}
   1.229 +
   1.230 +void sball_button(int bn, int state)
   1.231 +{
   1.232 +}
   1.233 +
   1.234 +int parse_args(int argc, char **argv)
   1.235 +{
   1.236 +	int i, loaded_something = 0;
   1.237 +
   1.238 +	for(i=0; i<argc; i++) {
   1.239 +		if(argv[i][0] == '-') {
   1.240 +			if(argv[i][2] != 0) {
   1.241 +				goto inval;
   1.242 +			}
   1.243 +			switch(argv[i][1]) {
   1.244 +			default:
   1.245 +				goto inval;
   1.246 +			}
   1.247 +		} else {
   1.248 +			if(scnfile_load(scn, argv[i])) {
   1.249 +				fprintf(stderr, "failed to load %s\n", argv[i]);
   1.250 +				return -1;
   1.251 +			}
   1.252 +			loaded_something = 1;
   1.253 +		}
   1.254 +	}
   1.255 +
   1.256 +	if(!loaded_something) {
   1.257 +		fprintf(stderr, "pass the filename(s) of the scene(s) you wish to view\n");
   1.258 +		return -1;
   1.259 +	}
   1.260 +	return 0;
   1.261 +
   1.262 +inval:
   1.263 +	fprintf(stderr, "invalid argument: %s\n", argv[i]);
   1.264 +	return -1;
   1.265 +}
     2.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     2.2 +++ b/src/file_milk.c	Sat Jan 21 04:14:24 2012 +0200
     2.3 @@ -0,0 +1,32 @@
     2.4 +#include <stdio.h>
     2.5 +#include <stdlib.h>
     2.6 +#include "scene.h"
     2.7 +
     2.8 +#ifdef __GNUC__
     2.9 +#define PACKED	__attribute__((packed))
    2.10 +#endif
    2.11 +
    2.12 +
    2.13 +struct header {
    2.14 +	char magic[10];
    2.15 +	int fmt_ver;
    2.16 +} PACKED;
    2.17 +
    2.18 +struct vertex {
    2.19 +	char flags;
    2.20 +	float pos[3];
    2.21 +	char bone_id;		/* -1 means no bone */
    2.22 +	char ref_count;
    2.23 +} PACKED;
    2.24 +
    2.25 +struct triangle {
    2.26 +	uint16_t flags;
    2.27 +	uint16_t v[3];
    2.28 +	float vnorm[3][3];
    2.29 +	float s[3];
    2.30 +	float t[3];
    2.31 +	unsigned char smoothing_group;
    2.32 +	unsigned char group_idx;
    2.33 +} PACKED;
    2.34 +
    2.35 +
     3.1 --- a/src/mesh.c	Sun Jan 15 08:32:19 2012 +0200
     3.2 +++ b/src/mesh.c	Sat Jan 21 04:14:24 2012 +0200
     3.3 @@ -94,6 +94,14 @@
     3.4  	return ma->elem_sz;
     3.5  }
     3.6  
     3.7 +void *vattr_elem(struct mesh_vertattr *ma, int elem)
     3.8 +{
     3.9 +	int count = dynarr_size(ma->data);
    3.10 +	if(elem >= count) {
    3.11 +		return 0;
    3.12 +	}
    3.13 +	return (char*)ma->data + elem * ma->elem_sz;
    3.14 +}
    3.15  
    3.16  
    3.17  /* -------- mesh -------- */
    3.18 @@ -116,7 +124,7 @@
    3.19  
    3.20  void mesh_destroy(struct mesh *m)
    3.21  {
    3.22 -	int i, nattr = mesh_attr_count(m);
    3.23 +	int i, nattr = mesh_num_attribs(m);
    3.24  
    3.25  	for(i=0; i<nattr; i++) {
    3.26  		vattr_destroy(m->attr + i);
    3.27 @@ -148,6 +156,11 @@
    3.28  	return m->name ? m->name : "<unnamed mesh>";
    3.29  }
    3.30  
    3.31 +int mesh_poly_type(struct mesh *m)
    3.32 +{
    3.33 +	return m->poly_nverts;
    3.34 +}
    3.35 +
    3.36  int mesh_add_attrib(struct mesh *m, struct mesh_vertattr *attr)
    3.37  {
    3.38  	struct mesh_polyidx pidx;
    3.39 @@ -171,9 +184,14 @@
    3.40  	return 0;
    3.41  }
    3.42  
    3.43 +int mesh_num_attribs(struct mesh *m)
    3.44 +{
    3.45 +	return dynarr_size(m->attr);
    3.46 +}
    3.47 +
    3.48  int mesh_find_attrib(struct mesh *m, const char *name)
    3.49  {
    3.50 -	int i, nattr = mesh_attr_count(m);
    3.51 +	int i, nattr = mesh_num_attribs(m);
    3.52  
    3.53  	for(i=0; i<nattr; i++) {
    3.54  		if(m->attr[i].name && strcmp(m->attr[i].name, name) == 0) {
    3.55 @@ -183,14 +201,30 @@
    3.56  	return -1;
    3.57  }
    3.58  
    3.59 -int mesh_attr_count(struct mesh *m)
    3.60 +struct mesh_vertattr *mesh_attrib(struct mesh *m, int loc)
    3.61  {
    3.62 -	return dynarr_size(m->attr);
    3.63 +	return loc >= 0 ? m->attr + loc : 0;
    3.64 +}
    3.65 +
    3.66 +void *mesh_attrib_data(struct mesh *m, int loc)
    3.67 +{
    3.68 +	return loc >= 0 ? m->attr[loc].data : 0;
    3.69 +}
    3.70 +
    3.71 +int *mesh_poly_data(struct mesh *m, int loc)
    3.72 +{
    3.73 +	return loc >= 0 ? m->polyidx[loc].data : 0;
    3.74 +}
    3.75 +
    3.76 +
    3.77 +int mesh_attrib_count(struct mesh *m, int loc)
    3.78 +{
    3.79 +	return loc >= 0 ? vattr_count(m->attr + loc) : 0;
    3.80  }
    3.81  
    3.82  int mesh_poly_count(struct mesh *m)
    3.83  {
    3.84 -	int i, nattr = mesh_attr_count(m);
    3.85 +	int i, nattr = mesh_num_attribs(m);
    3.86  
    3.87  	for(i=0; i<nattr; i++) {
    3.88  		int count = dynarr_empty(m->polyidx[i].data);
    3.89 @@ -201,9 +235,19 @@
    3.90  	return 0;
    3.91  }
    3.92  
    3.93 +void *mesh_attrib_elem(struct mesh *m, int loc, int elem)
    3.94 +{
    3.95 +	return loc >= 0 ? vattr_elem(m->attr + loc, elem) : 0;
    3.96 +}
    3.97 +
    3.98 +int mesh_attrib_elem_size(struct mesh *m, int loc)
    3.99 +{
   3.100 +	return loc >= 0 ? m->attr[loc].elem_sz : 0;
   3.101 +}
   3.102 +
   3.103  int mesh_add_polyref(struct mesh *m, int attr_loc, ...)
   3.104  {
   3.105 -	int i, nattr = mesh_attr_count(m);
   3.106 +	int i, nattr = mesh_num_attribs(m);
   3.107  	int *poly = alloca(m->poly_nverts * sizeof *poly);
   3.108  	va_list ap;
   3.109  	void *tmp;
     4.1 --- a/src/mesh.h	Sun Jan 15 08:32:19 2012 +0200
     4.2 +++ b/src/mesh.h	Sat Jan 21 04:14:24 2012 +0200
     4.3 @@ -22,6 +22,7 @@
     4.4  void *vattr_pointer(struct mesh_vertattr *ma);
     4.5  int vattr_count(struct mesh_vertattr *ma);
     4.6  int vattr_elem_size(struct mesh_vertattr *ma);
     4.7 +void *vattr_elem(struct mesh_vertattr *ma, int elem);
     4.8  
     4.9  /* --- mesh --- */
    4.10  
    4.11 @@ -31,12 +32,23 @@
    4.12  int mesh_set_name(struct mesh *m, const char *name);
    4.13  const char *mesh_get_name(struct mesh *m);
    4.14  
    4.15 +/* 1 - points, 2 - lines, 3 - triangles, 4 - quads */
    4.16 +int mesh_poly_type(struct mesh *m);
    4.17 +
    4.18  int mesh_add_attrib(struct mesh *m, struct mesh_vertattr *attr);
    4.19 +int mesh_num_attribs(struct mesh *m);
    4.20  int mesh_find_attrib(struct mesh *m, const char *name);
    4.21  
    4.22 -int mesh_attr_count(struct mesh *m);
    4.23 +struct mesh_vertattr *mesh_attrib(struct mesh *m, int loc);
    4.24 +void *mesh_attrib_data(struct mesh *m, int loc);
    4.25 +int *mesh_poly_data(struct mesh *m, int loc);
    4.26 +
    4.27 +int mesh_attrib_count(struct mesh *m, int loc);
    4.28  int mesh_poly_count(struct mesh *m);
    4.29  
    4.30 +void *mesh_attrib_elem(struct mesh *m, int loc, int elem);
    4.31 +int mesh_attrib_elem_size(struct mesh *m, int loc);
    4.32 +
    4.33  /* the variable arguments correspond to the N indices of the N-gon
    4.34   * for this particular vertex attribute (attr_loc, retrieved by
    4.35   * mesh_find_attrib)
     5.1 --- a/src/scene.c	Sun Jan 15 08:32:19 2012 +0200
     5.2 +++ b/src/scene.c	Sat Jan 21 04:14:24 2012 +0200
     5.3 @@ -1,5 +1,7 @@
     5.4 +#include <stdio.h>
     5.5  #include <stdlib.h>
     5.6  #include <string.h>
     5.7 +#include <errno.h>
     5.8  #include "scene.h"
     5.9  #include "dynarr.h"
    5.10  
    5.11 @@ -7,6 +9,19 @@
    5.12  	struct mesh **mesh;
    5.13  };
    5.14  
    5.15 +struct scnfile_io {
    5.16 +	void *uptr;	/* user-data */
    5.17 +
    5.18 +	size_t (*read)(void *buf, size_t bytes, void *uptr);
    5.19 +	size_t (*write)(void *buf, size_t bytes, void *uptr);
    5.20 +	long (*seek)(long offs, int whence, void *uptr);
    5.21 +};
    5.22 +
    5.23 +static size_t def_read(void *buf, size_t bytes, void *uptr);
    5.24 +static size_t def_write(void *buf, size_t bytes, void *uptr);
    5.25 +static long def_seek(long offset, int whence, void *uptr);
    5.26 +
    5.27 +
    5.28  int scnfile_init(struct scenefile *scn)
    5.29  {
    5.30  	if(!(scn->mesh = dynarr_alloc(0, sizeof *scn->mesh))) {
    5.31 @@ -59,6 +74,27 @@
    5.32  
    5.33  int scnfile_load(struct scenefile *scn, const char *fname)
    5.34  {
    5.35 +	FILE *fp;
    5.36 +	int res;
    5.37 +
    5.38 +	if(!(fp = fopen(fname, "rb"))) {
    5.39 +		fprintf(stderr, "scenefile: failed to load: %s: %s\n", fname, strerror(errno));
    5.40 +		return -1;
    5.41 +	}
    5.42 +	res = scnfile_read_file(scn, fp);
    5.43 +	fclose(fp);
    5.44 +	return res;
    5.45 +}
    5.46 +
    5.47 +int scnfile_read_file(struct scenefile *scn, FILE *fp)
    5.48 +{
    5.49 +	struct scnfile_io io = {0, def_read, def_write, def_seek};
    5.50 +	io.uptr = fp;
    5.51 +	return scnfile_read(scn, &io);
    5.52 +}
    5.53 +
    5.54 +int scnfile_read(struct scenefile *scn, struct scnfile_io *io)
    5.55 +{
    5.56  	return -1;	/* TODO */
    5.57  }
    5.58  
    5.59 @@ -86,3 +122,44 @@
    5.60  {
    5.61  	return dynarr_size(scn->mesh);
    5.62  }
    5.63 +
    5.64 +
    5.65 +void scnfile_io_user_data(struct scnfile_io *io, void *uptr)
    5.66 +{
    5.67 +	io->uptr = uptr;
    5.68 +}
    5.69 +
    5.70 +void scnfile_io_read_func(struct scnfile_io *io, size_t (*read)(void*, size_t, void*))
    5.71 +{
    5.72 +	io->read = read;
    5.73 +}
    5.74 +
    5.75 +void scnfile_io_write_func(struct scnfile_io *io, size_t (*write)(void*, size_t, void*))
    5.76 +{
    5.77 +	io->write = write;
    5.78 +}
    5.79 +
    5.80 +void scnfile_io_seek_func(struct scnfile_io *io, long (*seek)(long, int, void*))
    5.81 +{
    5.82 +	io->seek = seek;
    5.83 +}
    5.84 +
    5.85 +
    5.86 +static size_t def_read(void *buf, size_t bytes, void *uptr)
    5.87 +{
    5.88 +	return uptr ? fread(buf, 1, bytes, uptr) : 0;
    5.89 +}
    5.90 +
    5.91 +static size_t def_write(void *buf, size_t bytes, void *uptr)
    5.92 +{
    5.93 +	return uptr ? fwrite(buf, 1, bytes, uptr) : 0;
    5.94 +}
    5.95 +
    5.96 +static long def_seek(long offset, int whence, void *uptr)
    5.97 +{
    5.98 +	if(!uptr || fseek(uptr, offset, whence) == -1) {
    5.99 +		return -1;
   5.100 +	}
   5.101 +	return ftell(uptr);
   5.102 +}
   5.103 +
     6.1 --- a/src/scene.h	Sun Jan 15 08:32:19 2012 +0200
     6.2 +++ b/src/scene.h	Sat Jan 21 04:14:24 2012 +0200
     6.3 @@ -4,6 +4,7 @@
     6.4  #include "mesh.h"
     6.5  
     6.6  struct scenefile;
     6.7 +struct scnfile_io;
     6.8  
     6.9  #ifdef __cplusplus
    6.10  extern "C" {
    6.11 @@ -20,11 +21,49 @@
    6.12  
    6.13  
    6.14  int scnfile_load(struct scenefile *scn, const char *fname);
    6.15 +int scnfile_read_file(struct scenefile *scn, FILE *fp);
    6.16 +int scnfile_read(struct scenefile *scn, struct scnfile_io *io);
    6.17  
    6.18  int scnfile_find_mesh(struct scenefile *scn, const char *fname);
    6.19  struct mesh *scnfile_mesh(struct scenefile *scn, int idx);
    6.20  int scnfile_count(struct scenefile *scn);
    6.21  
    6.22 +
    6.23 +/* These functions can be used to fill an scnfile_io struct before it's passed to
    6.24 + * one of the user-defined i/o image reading/writing functions (scnfile_read/scnfile_write).
    6.25 + *
    6.26 + * User-defined i/o functions:
    6.27 + *
    6.28 + * - size_t read_func(void *buffer, size_t bytes, void *user_ptr)
    6.29 + * Must try to fill the buffer with the specified number of bytes, and return
    6.30 + * the number of bytes actually read.
    6.31 + *
    6.32 + * - size_t write_func(void *buffer, size_t bytes, void *user_ptr)
    6.33 + * Must write the specified number of bytes from the supplied buffer and return
    6.34 + * the number of bytes actually written.
    6.35 + *
    6.36 + * - long seek_func(long offset, int whence, void *user_ptr)
    6.37 + * Must seek offset bytes from: the beginning of the file if whence is SEEK_SET,
    6.38 + * the current position if whence is SEEK_CUR, or the end of the file if whence is
    6.39 + * SEEK_END, and return the resulting file offset from the beginning of the file.
    6.40 + * (i.e. seek_func(0, SEEK_CUR, user_ptr); must be equivalent to an ftell).
    6.41 + *
    6.42 + * All three functions get the user-data pointer set through scnfile_io_set_user_data
    6.43 + * as their last argument.
    6.44 + *
    6.45 + * Note: obviously you don't need to set a write function if you're only going
    6.46 + * to call scnfile_read, or the read and seek function if you're only going to call
    6.47 + * scnfile_write.
    6.48 + *
    6.49 + * Note: if the user-supplied write function is buffered, make sure to flush
    6.50 + * (or close the file) after scnfile_write returns.
    6.51 + */
    6.52 +void scnfile_io_user_data(struct scnfile_io *io, void *uptr);
    6.53 +void scnfile_io_read_func(struct scnfile_io *io, size_t (*read)(void*, size_t, void*));
    6.54 +void scnfile_io_write_func(struct scnfile_io *io, size_t (*write)(void*, size_t, void*));
    6.55 +void scnfile_io_seek_func(struct scnfile_io *io, long (*seek)(long, int, void*));
    6.56 +
    6.57 +
    6.58  #ifdef __cplusplus
    6.59  }
    6.60  #endif