doorbell

changeset 0:a5755687dd75

initial commit
author John Tsiombikas <nuclear@member.fsf.org>
date Tue, 08 Mar 2016 03:26:01 +0200
parents
children daade2a35e69 d3f2a2b19504
files .hgignore spycam/Makefile spycam/src/main.cc spycam/src/sdr.c spycam/src/sdr.h spycam/src/spycam.cc spycam/src/spycam.h
diffstat 7 files changed, 831 insertions(+), 0 deletions(-) [+]
line diff
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/.hgignore	Tue Mar 08 03:26:01 2016 +0200
     1.3 @@ -0,0 +1,4 @@
     1.4 +\.o$
     1.5 +\.d$
     1.6 +\.swp$
     1.7 +spycam$
     2.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     2.2 +++ b/spycam/Makefile	Tue Mar 08 03:26:01 2016 +0200
     2.3 @@ -0,0 +1,19 @@
     2.4 +src = $(wildcard src/*.cc)
     2.5 +csrc = $(wildcard src/*.c)
     2.6 +obj = $(src:.cc=.o) $(csrc:.c=.o)
     2.7 +bin = spycam
     2.8 +
     2.9 +warn = -pedantic -Wall
    2.10 +opt = -O0
    2.11 +dbg = -g
    2.12 +
    2.13 +CFLAGS = $(warn) $(opt) $(dbg)
    2.14 +CXXFLAGS = $(warn) $(opt) $(dbg)
    2.15 +LDFLAGS = -lX11 -lEGL -lGLESv2 -lm -lgmath
    2.16 +
    2.17 +$(bin): $(obj)
    2.18 +	$(CXX) -o $@ $(obj) $(LDFLAGS)
    2.19 +
    2.20 +.PHONY: clean
    2.21 +clean:
    2.22 +	rm -f $(obj) $(bin)
     3.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     3.2 +++ b/spycam/src/main.cc	Tue Mar 08 03:26:01 2016 +0200
     3.3 @@ -0,0 +1,236 @@
     3.4 +#include <stdio.h>
     3.5 +#include <stdlib.h>
     3.6 +#include <unistd.h>
     3.7 +#include <sys/select.h>
     3.8 +#include <X11/Xlib.h>
     3.9 +#include <X11/Xatom.h>
    3.10 +#include <GLES2/gl2.h>
    3.11 +#include <EGL/egl.h>
    3.12 +#include "spycam.h"
    3.13 +
    3.14 +static void cleanup();
    3.15 +static bool create_glwin(int xsz, int ysz);
    3.16 +static bool handle_event(XEvent *ev);
    3.17 +static void set_window_title(const char *title);
    3.18 +
    3.19 +static int win_width, win_height;
    3.20 +static bool quit, redraw_pending;
    3.21 +static Display *dpy;
    3.22 +static Window win;
    3.23 +static EGLDisplay egl_dpy;
    3.24 +static EGLContext egl_ctx;
    3.25 +static EGLSurface egl_win;
    3.26 +static Atom xa_wm_proto, xa_del_window;
    3.27 +
    3.28 +int main(int argc, char **argv)
    3.29 +{
    3.30 +	if(!(dpy = XOpenDisplay(0))) {
    3.31 +		fprintf(stderr, "failed to connect to the X server.\n");
    3.32 +		return 1;
    3.33 +	}
    3.34 +	xa_wm_proto = XInternAtom(dpy, "WM_PROTOCOLS", False);
    3.35 +	xa_del_window = XInternAtom(dpy, "WM_DELETE_WINDOW", False);
    3.36 +
    3.37 +	egl_dpy = eglGetDisplay(dpy);
    3.38 +	int egl_ver_major, egl_ver_minor;
    3.39 +	if(!eglInitialize(egl_dpy, &egl_ver_major, &egl_ver_minor)) {
    3.40 +		fprintf(stderr, "failed to initialize EGL\n");
    3.41 +		return 1;
    3.42 +	}
    3.43 +	printf("initialized EGL %d.%d\n", egl_ver_major, egl_ver_minor);
    3.44 +
    3.45 +	if(!create_glwin(800, 600)) {
    3.46 +		cleanup();
    3.47 +		return 1;
    3.48 +	}
    3.49 +
    3.50 +	if(!app_init()) {
    3.51 +		cleanup();
    3.52 +		return 1;
    3.53 +	}
    3.54 +
    3.55 +	for(;;) {
    3.56 +		while(XPending(dpy) || !redraw_pending) {
    3.57 +			XEvent ev;
    3.58 +			XNextEvent(dpy, &ev);
    3.59 +			if(!handle_event(&ev) || quit) {
    3.60 +				goto break_main_loop;
    3.61 +			}
    3.62 +		}
    3.63 +
    3.64 +		if(redraw_pending) {
    3.65 +			app_draw();
    3.66 +			eglSwapBuffers(egl_dpy, egl_win);
    3.67 +		}
    3.68 +	}
    3.69 +break_main_loop:
    3.70 +
    3.71 +	cleanup();
    3.72 +	return 0;
    3.73 +}
    3.74 +
    3.75 +void app_quit()
    3.76 +{
    3.77 +	quit = true;
    3.78 +}
    3.79 +
    3.80 +void app_redisplay()
    3.81 +{
    3.82 +	redraw_pending = true;
    3.83 +}
    3.84 +
    3.85 +static void cleanup()
    3.86 +{
    3.87 +	if(egl_dpy) {
    3.88 +		eglMakeCurrent(egl_dpy, 0, 0, 0);
    3.89 +		if(egl_win)
    3.90 +			eglDestroySurface(egl_dpy, egl_win);
    3.91 +		if(egl_ctx)
    3.92 +			eglDestroyContext(egl_dpy, egl_ctx);
    3.93 +		eglTerminate(egl_dpy);
    3.94 +	}
    3.95 +	if(dpy) {
    3.96 +		if(win)
    3.97 +			XDestroyWindow(dpy, win);
    3.98 +		XCloseDisplay(dpy);
    3.99 +	}
   3.100 +}
   3.101 +
   3.102 +static bool create_glwin(int xsz, int ysz)
   3.103 +{
   3.104 +	static const int egl_attr[] = {
   3.105 +		EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
   3.106 +		EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
   3.107 +		EGL_RED_SIZE, 5,
   3.108 +		EGL_GREEN_SIZE, 5,
   3.109 +		EGL_BLUE_SIZE, 5,
   3.110 +		EGL_DEPTH_SIZE, 16,
   3.111 +		EGL_NONE
   3.112 +	};
   3.113 +
   3.114 +	int scr = DefaultScreen(dpy);
   3.115 +	Window root_win = RootWindow(dpy, scr);
   3.116 +
   3.117 +	EGLConfig cfg;
   3.118 +	int num_cfg;
   3.119 +	if(!eglChooseConfig(egl_dpy, egl_attr, &cfg, 1, &num_cfg)) {
   3.120 +		fprintf(stderr, "failed to find matching EGL visual\n");
   3.121 +		return false;
   3.122 +	}
   3.123 +	int rsize, gsize, bsize, zsize, ssize, vis_id;
   3.124 +	eglGetConfigAttrib(egl_dpy, cfg, EGL_RED_SIZE, &rsize);
   3.125 +	eglGetConfigAttrib(egl_dpy, cfg, EGL_GREEN_SIZE, &gsize);
   3.126 +	eglGetConfigAttrib(egl_dpy, cfg, EGL_BLUE_SIZE, &bsize);
   3.127 +	eglGetConfigAttrib(egl_dpy, cfg, EGL_DEPTH_SIZE, &zsize);
   3.128 +	eglGetConfigAttrib(egl_dpy, cfg, EGL_STENCIL_SIZE, &ssize);
   3.129 +	eglGetConfigAttrib(egl_dpy, cfg, EGL_NATIVE_VISUAL_ID, &vis_id);
   3.130 +	printf("got visual %d: %d bpp (%d%d%d), %d zbuffer, %d stencil\n", vis_id, rsize + gsize + bsize,
   3.131 +			rsize, gsize, bsize, zsize, ssize);
   3.132 +
   3.133 +	int num_vis;
   3.134 +	XVisualInfo *vis_info, vis_template;
   3.135 +	vis_template.visualid = vis_id;
   3.136 +	if(!(vis_info = XGetVisualInfo(dpy, VisualIDMask, &vis_template, &num_vis))) {
   3.137 +		fprintf(stderr, "visual id %d is invalid (?!)\n", vis_id);
   3.138 +		return false;
   3.139 +	}
   3.140 +
   3.141 +	XSetWindowAttributes xattr;
   3.142 +	xattr.border_pixel = xattr.backing_pixel = BlackPixel(dpy, scr);
   3.143 +	xattr.colormap = XCreateColormap(dpy, root_win, vis_info->visual, AllocNone);
   3.144 +	unsigned int xattr_mask = CWColormap | CWBorderPixel | CWBackPixel;
   3.145 +
   3.146 +	win = XCreateWindow(dpy, root_win, 0, 0, xsz, ysz, 0, vis_info->depth, InputOutput,
   3.147 +			vis_info->visual, xattr_mask, &xattr);
   3.148 +	if(!win) {
   3.149 +		fprintf(stderr, "failed to create window\n");
   3.150 +		XFree(vis_info);
   3.151 +		return false;
   3.152 +	}
   3.153 +	XFree(vis_info);
   3.154 +	XSelectInput(dpy, win, ExposureMask | StructureNotifyMask | KeyPressMask | KeyReleaseMask);
   3.155 +
   3.156 +	XSetWMProtocols(dpy, win, &xa_del_window, 1);
   3.157 +	set_window_title("spycam");
   3.158 +
   3.159 +	eglBindAPI(EGL_OPENGL_ES_API);
   3.160 +
   3.161 +	if(!(egl_win = eglCreateWindowSurface(egl_dpy, cfg, win, 0))) {
   3.162 +		fprintf(stderr, "failed to create EGL window\n");
   3.163 +		XDestroyWindow(dpy, win);
   3.164 +		return false;
   3.165 +	}
   3.166 +
   3.167 +	static const int ctxattr[] = { EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE };
   3.168 +	if(!(egl_ctx = eglCreateContext(egl_dpy, cfg, EGL_NO_CONTEXT, ctxattr))) {
   3.169 +		fprintf(stderr, "failed to create EGL context\n");
   3.170 +		eglDestroySurface(egl_dpy, egl_win);
   3.171 +		XDestroyWindow(dpy, win);
   3.172 +		return false;
   3.173 +	}
   3.174 +	eglMakeCurrent(egl_dpy, egl_win, egl_win, egl_ctx);
   3.175 +
   3.176 +	XMapWindow(dpy, win);
   3.177 +
   3.178 +	eglQuerySurface(dpy, egl_win, EGL_WIDTH, &win_width);
   3.179 +	eglQuerySurface(dpy, egl_win, EGL_HEIGHT, &win_height);
   3.180 +	app_reshape(win_width, win_height);
   3.181 +
   3.182 +	return true;
   3.183 +}
   3.184 +
   3.185 +static bool handle_event(XEvent *ev)
   3.186 +{
   3.187 +	static bool mapped;
   3.188 +
   3.189 +	switch(ev->type) {
   3.190 +	case Expose:
   3.191 +		if(mapped) {
   3.192 +			redraw_pending = true;
   3.193 +		}
   3.194 +		break;
   3.195 +
   3.196 +	case MapNotify:
   3.197 +		mapped = true;
   3.198 +		redraw_pending = true;
   3.199 +		break;
   3.200 +
   3.201 +	case UnmapNotify:
   3.202 +		mapped = false;
   3.203 +		redraw_pending = false;
   3.204 +		break;
   3.205 +
   3.206 +	case ConfigureNotify:
   3.207 +		if(win_width != (int)ev->xconfigure.width || win_height != (int)ev->xconfigure.height) {
   3.208 +			win_width = ev->xconfigure.width;
   3.209 +			win_height = ev->xconfigure.height;
   3.210 +			app_reshape(win_width, win_height);
   3.211 +		}
   3.212 +		break;
   3.213 +
   3.214 +	case KeyPress:
   3.215 +	case KeyRelease:
   3.216 +		app_keyboard(XLookupKeysym(&ev->xkey, 0) & 0xff, ev->type == KeyPress);
   3.217 +		break;
   3.218 +
   3.219 +	case ClientMessage:
   3.220 +		if(ev->xclient.message_type == xa_wm_proto &&
   3.221 +				(Atom)ev->xclient.data.l[0] == xa_del_window) {
   3.222 +			return false;
   3.223 +		}
   3.224 +		break;
   3.225 +
   3.226 +	default:
   3.227 +		break;
   3.228 +	}
   3.229 +	return true;
   3.230 +}
   3.231 +
   3.232 +static void set_window_title(const char *title)
   3.233 +{
   3.234 +	XTextProperty text_prop;
   3.235 +	XStringListToTextProperty((char**)&title, 1, &text_prop);
   3.236 +	XSetWMName(dpy, win, &text_prop);
   3.237 +	XSetWMIconName(dpy, win, &text_prop);
   3.238 +	XFree(text_prop.value);
   3.239 +}
     4.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     4.2 +++ b/spycam/src/sdr.c	Tue Mar 08 03:26:01 2016 +0200
     4.3 @@ -0,0 +1,407 @@
     4.4 +#include <stdio.h>
     4.5 +#include <stdlib.h>
     4.6 +#include <string.h>
     4.7 +#include <errno.h>
     4.8 +#include <stdarg.h>
     4.9 +#include <assert.h>
    4.10 +#include <GLES2/gl2.h>
    4.11 +
    4.12 +#if defined(unix) || defined(__unix__)
    4.13 +#include <unistd.h>
    4.14 +#include <sys/stat.h>
    4.15 +#endif	/* unix */
    4.16 +
    4.17 +#include "sdr.h"
    4.18 +
    4.19 +static const char *sdrtypestr(unsigned int sdrtype);
    4.20 +
    4.21 +unsigned int create_vertex_shader(const char *src)
    4.22 +{
    4.23 +	return create_shader(src, GL_VERTEX_SHADER);
    4.24 +}
    4.25 +
    4.26 +unsigned int create_pixel_shader(const char *src)
    4.27 +{
    4.28 +	return create_shader(src, GL_FRAGMENT_SHADER);
    4.29 +}
    4.30 +
    4.31 +unsigned int create_tessctl_shader(const char *src)
    4.32 +{
    4.33 +#ifdef GL_TESS_CONTROL_SHADER
    4.34 +	return create_shader(src, GL_TESS_CONTROL_SHADER);
    4.35 +#else
    4.36 +	return 0;
    4.37 +#endif
    4.38 +}
    4.39 +
    4.40 +unsigned int create_tesseval_shader(const char *src)
    4.41 +{
    4.42 +#ifdef GL_TESS_EVALUATION_SHADER
    4.43 +	return create_shader(src, GL_TESS_EVALUATION_SHADER);
    4.44 +#else
    4.45 +	return 0;
    4.46 +#endif
    4.47 +}
    4.48 +
    4.49 +unsigned int create_geometry_shader(const char *src)
    4.50 +{
    4.51 +#ifdef GL_GEOMETRY_SHADER
    4.52 +	return create_shader(src, GL_GEOMETRY_SHADER);
    4.53 +#else
    4.54 +	return 0;
    4.55 +#endif
    4.56 +}
    4.57 +
    4.58 +unsigned int create_shader(const char *src, unsigned int sdr_type)
    4.59 +{
    4.60 +	unsigned int sdr;
    4.61 +	int success, info_len;
    4.62 +	char *info_str = 0;
    4.63 +	GLenum err;
    4.64 +
    4.65 +	sdr = glCreateShader(sdr_type);
    4.66 +	assert(glGetError() == GL_NO_ERROR);
    4.67 +	glShaderSource(sdr, 1, &src, 0);
    4.68 +	err = glGetError();
    4.69 +	assert(err == GL_NO_ERROR);
    4.70 +	glCompileShader(sdr);
    4.71 +	assert(glGetError() == GL_NO_ERROR);
    4.72 +
    4.73 +	glGetShaderiv(sdr, GL_COMPILE_STATUS, &success);
    4.74 +	assert(glGetError() == GL_NO_ERROR);
    4.75 +	glGetShaderiv(sdr, GL_INFO_LOG_LENGTH, &info_len);
    4.76 +	assert(glGetError() == GL_NO_ERROR);
    4.77 +
    4.78 +	if(info_len) {
    4.79 +		if((info_str = malloc(info_len + 1))) {
    4.80 +			glGetShaderInfoLog(sdr, info_len, 0, info_str);
    4.81 +			assert(glGetError() == GL_NO_ERROR);
    4.82 +			info_str[info_len] = 0;
    4.83 +		}
    4.84 +	}
    4.85 +
    4.86 +	if(success) {
    4.87 +		fprintf(stderr, info_str ? "done: %s\n" : "done\n", info_str);
    4.88 +	} else {
    4.89 +		fprintf(stderr, info_str ? "failed: %s\n" : "failed\n", info_str);
    4.90 +		glDeleteShader(sdr);
    4.91 +		sdr = 0;
    4.92 +	}
    4.93 +
    4.94 +	free(info_str);
    4.95 +	return sdr;
    4.96 +}
    4.97 +
    4.98 +void free_shader(unsigned int sdr)
    4.99 +{
   4.100 +	glDeleteShader(sdr);
   4.101 +}
   4.102 +
   4.103 +unsigned int load_vertex_shader(const char *fname)
   4.104 +{
   4.105 +	return load_shader(fname, GL_VERTEX_SHADER);
   4.106 +}
   4.107 +
   4.108 +unsigned int load_pixel_shader(const char *fname)
   4.109 +{
   4.110 +	return load_shader(fname, GL_FRAGMENT_SHADER);
   4.111 +}
   4.112 +
   4.113 +unsigned int load_tessctl_shader(const char *fname)
   4.114 +{
   4.115 +#ifdef GL_TESS_CONTROL_SHADER
   4.116 +	return load_shader(fname, GL_TESS_CONTROL_SHADER);
   4.117 +#else
   4.118 +	return 0;
   4.119 +#endif
   4.120 +}
   4.121 +
   4.122 +unsigned int load_tesseval_shader(const char *fname)
   4.123 +{
   4.124 +#ifdef GL_TESS_EVALUATION_SHADER
   4.125 +	return load_shader(fname, GL_TESS_EVALUATION_SHADER);
   4.126 +#else
   4.127 +	return 0;
   4.128 +#endif
   4.129 +}
   4.130 +
   4.131 +unsigned int load_geometry_shader(const char *fname)
   4.132 +{
   4.133 +#ifdef GL_GEOMETRY_SHADER
   4.134 +	return load_shader(fname, GL_GEOMETRY_SHADER);
   4.135 +#else
   4.136 +	return 0;
   4.137 +#endif
   4.138 +}
   4.139 +
   4.140 +unsigned int load_shader(const char *fname, unsigned int sdr_type)
   4.141 +{
   4.142 +	unsigned int sdr;
   4.143 +	size_t filesize;
   4.144 +	FILE *fp;
   4.145 +	char *src;
   4.146 +
   4.147 +	if(!(fp = fopen(fname, "rb"))) {
   4.148 +		fprintf(stderr, "failed to open shader %s: %s\n", fname, strerror(errno));
   4.149 +		return 0;
   4.150 +	}
   4.151 +
   4.152 +	fseek(fp, 0, SEEK_END);
   4.153 +	filesize = ftell(fp);
   4.154 +	fseek(fp, 0, SEEK_SET);
   4.155 +
   4.156 +	if(!(src = malloc(filesize + 1))) {
   4.157 +		fclose(fp);
   4.158 +		return 0;
   4.159 +	}
   4.160 +	fread(src, 1, filesize, fp);
   4.161 +	src[filesize] = 0;
   4.162 +	fclose(fp);
   4.163 +
   4.164 +	fprintf(stderr, "compiling %s shader: %s... ", sdrtypestr(sdr_type), fname);
   4.165 +	sdr = create_shader(src, sdr_type);
   4.166 +
   4.167 +	free(src);
   4.168 +	return sdr;
   4.169 +}
   4.170 +
   4.171 +
   4.172 +/* ---- gpu programs ---- */
   4.173 +
   4.174 +unsigned int create_program(void)
   4.175 +{
   4.176 +	unsigned int prog = glCreateProgram();
   4.177 +	assert(glGetError() == GL_NO_ERROR);
   4.178 +	return prog;
   4.179 +}
   4.180 +
   4.181 +unsigned int create_program_link(unsigned int sdr0, ...)
   4.182 +{
   4.183 +	unsigned int prog, sdr;
   4.184 +	va_list ap;
   4.185 +
   4.186 +	if(!(prog = create_program())) {
   4.187 +		return 0;
   4.188 +	}
   4.189 +
   4.190 +	attach_shader(prog, sdr0);
   4.191 +	if(glGetError()) {
   4.192 +		return 0;
   4.193 +	}
   4.194 +
   4.195 +	va_start(ap, sdr0);
   4.196 +	while((sdr = va_arg(ap, unsigned int))) {
   4.197 +		attach_shader(prog, sdr);
   4.198 +		if(glGetError()) {
   4.199 +			return 0;
   4.200 +		}
   4.201 +	}
   4.202 +	va_end(ap);
   4.203 +
   4.204 +	if(link_program(prog) == -1) {
   4.205 +		free_program(prog);
   4.206 +		return 0;
   4.207 +	}
   4.208 +	return prog;
   4.209 +}
   4.210 +
   4.211 +unsigned int create_program_load(const char *vfile, const char *pfile)
   4.212 +{
   4.213 +	unsigned int vs = 0, ps = 0;
   4.214 +
   4.215 +	if(vfile && *vfile && !(vs = load_vertex_shader(vfile))) {
   4.216 +		return 0;
   4.217 +	}
   4.218 +	if(pfile && *pfile && !(ps = load_pixel_shader(pfile))) {
   4.219 +		return 0;
   4.220 +	}
   4.221 +	return create_program_link(vs, ps, 0);
   4.222 +}
   4.223 +
   4.224 +void free_program(unsigned int sdr)
   4.225 +{
   4.226 +	glDeleteProgram(sdr);
   4.227 +}
   4.228 +
   4.229 +void attach_shader(unsigned int prog, unsigned int sdr)
   4.230 +{
   4.231 +	int err;
   4.232 +
   4.233 +	if(prog && sdr) {
   4.234 +		assert(glGetError() == GL_NO_ERROR);
   4.235 +		glAttachShader(prog, sdr);
   4.236 +		if((err = glGetError()) != GL_NO_ERROR) {
   4.237 +			fprintf(stderr, "failed to attach shader %u to program %u (err: 0x%x)\n", sdr, prog, err);
   4.238 +			abort();
   4.239 +		}
   4.240 +	}
   4.241 +}
   4.242 +
   4.243 +int link_program(unsigned int prog)
   4.244 +{
   4.245 +	int linked, info_len, retval = 0;
   4.246 +	char *info_str = 0;
   4.247 +
   4.248 +	glLinkProgram(prog);
   4.249 +	assert(glGetError() == GL_NO_ERROR);
   4.250 +	glGetProgramiv(prog, GL_LINK_STATUS, &linked);
   4.251 +	assert(glGetError() == GL_NO_ERROR);
   4.252 +	glGetProgramiv(prog, GL_INFO_LOG_LENGTH, &info_len);
   4.253 +	assert(glGetError() == GL_NO_ERROR);
   4.254 +
   4.255 +	if(info_len) {
   4.256 +		if((info_str = malloc(info_len + 1))) {
   4.257 +			glGetProgramInfoLog(prog, info_len, 0, info_str);
   4.258 +			assert(glGetError() == GL_NO_ERROR);
   4.259 +			info_str[info_len] = 0;
   4.260 +		}
   4.261 +	}
   4.262 +
   4.263 +	if(linked) {
   4.264 +		fprintf(stderr, info_str ? "linking done: %s\n" : "linking done\n", info_str);
   4.265 +	} else {
   4.266 +		fprintf(stderr, info_str ? "linking failed: %s\n" : "linking failed\n", info_str);
   4.267 +		retval = -1;
   4.268 +	}
   4.269 +
   4.270 +	free(info_str);
   4.271 +	return retval;
   4.272 +}
   4.273 +
   4.274 +int bind_program(unsigned int prog)
   4.275 +{
   4.276 +	GLenum err;
   4.277 +
   4.278 +	glUseProgram(prog);
   4.279 +	if(prog && (err = glGetError()) != GL_NO_ERROR) {
   4.280 +		/* maybe the program is not linked, try linking first */
   4.281 +		if(err == GL_INVALID_OPERATION) {
   4.282 +			if(link_program(prog) == -1) {
   4.283 +				return -1;
   4.284 +			}
   4.285 +			glUseProgram(prog);
   4.286 +			return glGetError() == GL_NO_ERROR ? 0 : -1;
   4.287 +		}
   4.288 +		return -1;
   4.289 +	}
   4.290 +	return 0;
   4.291 +}
   4.292 +
   4.293 +/* ugly but I'm not going to write the same bloody code over and over */
   4.294 +#define BEGIN_UNIFORM_CODE \
   4.295 +	int loc, curr_prog; \
   4.296 +	glGetIntegerv(GL_CURRENT_PROGRAM, &curr_prog); \
   4.297 +	if((unsigned int)curr_prog != prog && bind_program(prog) == -1) { \
   4.298 +		return -1; \
   4.299 +	} \
   4.300 +	if((loc = glGetUniformLocation(prog, name)) != -1)
   4.301 +
   4.302 +#define END_UNIFORM_CODE \
   4.303 +	if((unsigned int)curr_prog != prog) { \
   4.304 +		bind_program(curr_prog); \
   4.305 +	} \
   4.306 +	return loc == -1 ? -1 : 0
   4.307 +
   4.308 +int set_uniform_int(unsigned int prog, const char *name, int val)
   4.309 +{
   4.310 +	BEGIN_UNIFORM_CODE {
   4.311 +		glUniform1i(loc, val);
   4.312 +	}
   4.313 +	END_UNIFORM_CODE;
   4.314 +}
   4.315 +
   4.316 +int set_uniform_float(unsigned int prog, const char *name, float val)
   4.317 +{
   4.318 +	BEGIN_UNIFORM_CODE {
   4.319 +		glUniform1f(loc, val);
   4.320 +	}
   4.321 +	END_UNIFORM_CODE;
   4.322 +}
   4.323 +
   4.324 +int set_uniform_float2(unsigned int prog, const char *name, float x, float y)
   4.325 +{
   4.326 +	BEGIN_UNIFORM_CODE {
   4.327 +		glUniform2f(loc, x, y);
   4.328 +	}
   4.329 +	END_UNIFORM_CODE;
   4.330 +}
   4.331 +
   4.332 +int set_uniform_float3(unsigned int prog, const char *name, float x, float y, float z)
   4.333 +{
   4.334 +	BEGIN_UNIFORM_CODE {
   4.335 +		glUniform3f(loc, x, y, z);
   4.336 +	}
   4.337 +	END_UNIFORM_CODE;
   4.338 +}
   4.339 +
   4.340 +int set_uniform_float4(unsigned int prog, const char *name, float x, float y, float z, float w)
   4.341 +{
   4.342 +	BEGIN_UNIFORM_CODE {
   4.343 +		glUniform4f(loc, x, y, z, w);
   4.344 +	}
   4.345 +	END_UNIFORM_CODE;
   4.346 +}
   4.347 +
   4.348 +int set_uniform_matrix4(unsigned int prog, const char *name, float *mat)
   4.349 +{
   4.350 +	BEGIN_UNIFORM_CODE {
   4.351 +		glUniformMatrix4fv(loc, 1, GL_FALSE, mat);
   4.352 +	}
   4.353 +	END_UNIFORM_CODE;
   4.354 +}
   4.355 +
   4.356 +int set_uniform_matrix4_transposed(unsigned int prog, const char *name, float *mat)
   4.357 +{
   4.358 +	BEGIN_UNIFORM_CODE {
   4.359 +		glUniformMatrix4fv(loc, 1, GL_TRUE, mat);
   4.360 +	}
   4.361 +	END_UNIFORM_CODE;
   4.362 +}
   4.363 +
   4.364 +int get_attrib_loc(unsigned int prog, const char *name)
   4.365 +{
   4.366 +	int loc, curr_prog;
   4.367 +
   4.368 +	glGetIntegerv(GL_CURRENT_PROGRAM, &curr_prog);
   4.369 +	if((unsigned int)curr_prog != prog && bind_program(prog) == -1) {
   4.370 +		return -1;
   4.371 +	}
   4.372 +
   4.373 +	loc = glGetAttribLocation(prog, (char*)name);
   4.374 +
   4.375 +	if((unsigned int)curr_prog != prog) {
   4.376 +		bind_program(curr_prog);
   4.377 +	}
   4.378 +	return loc;
   4.379 +}
   4.380 +
   4.381 +void set_attrib_float3(int attr_loc, float x, float y, float z)
   4.382 +{
   4.383 +	glVertexAttrib3f(attr_loc, x, y, z);
   4.384 +}
   4.385 +
   4.386 +static const char *sdrtypestr(unsigned int sdrtype)
   4.387 +{
   4.388 +	switch(sdrtype) {
   4.389 +	case GL_VERTEX_SHADER:
   4.390 +		return "vertex";
   4.391 +	case GL_FRAGMENT_SHADER:
   4.392 +		return "pixel";
   4.393 +#ifdef GL_TESS_CONTROL_SHADER
   4.394 +	case GL_TESS_CONTROL_SHADER:
   4.395 +		return "tessellation control";
   4.396 +#endif
   4.397 +#ifdef GL_TESS_EVALUATION_SHADER
   4.398 +	case GL_TESS_EVALUATION_SHADER:
   4.399 +		return "tessellation evaluation";
   4.400 +#endif
   4.401 +#ifdef GL_GEOMETRY_SHADER
   4.402 +	case GL_GEOMETRY_SHADER:
   4.403 +		return "geometry";
   4.404 +#endif
   4.405 +
   4.406 +	default:
   4.407 +		break;
   4.408 +	}
   4.409 +	return "<unknown>";
   4.410 +}
     5.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     5.2 +++ b/spycam/src/sdr.h	Tue Mar 08 03:26:01 2016 +0200
     5.3 @@ -0,0 +1,52 @@
     5.4 +#ifndef SDR_H_
     5.5 +#define SDR_H_
     5.6 +
     5.7 +#ifdef __cplusplus
     5.8 +extern "C" {
     5.9 +#endif	/* __cplusplus */
    5.10 +
    5.11 +/* ---- shaders ---- */
    5.12 +unsigned int create_vertex_shader(const char *src);
    5.13 +unsigned int create_pixel_shader(const char *src);
    5.14 +unsigned int create_tessctl_shader(const char *src);
    5.15 +unsigned int create_tesseval_shader(const char *src);
    5.16 +unsigned int create_geometry_shader(const char *src);
    5.17 +unsigned int create_shader(const char *src, unsigned int sdr_type);
    5.18 +void free_shader(unsigned int sdr);
    5.19 +
    5.20 +unsigned int load_vertex_shader(const char *fname);
    5.21 +unsigned int load_pixel_shader(const char *fname);
    5.22 +unsigned int load_tessctl_shader(const char *fname);
    5.23 +unsigned int load_tesseval_shader(const char *fname);
    5.24 +unsigned int load_geometry_shader(const char *fname);
    5.25 +unsigned int load_shader(const char *src, unsigned int sdr_type);
    5.26 +
    5.27 +int add_shader(const char *fname, unsigned int sdr);
    5.28 +int remove_shader(const char *fname);
    5.29 +
    5.30 +/* ---- gpu programs ---- */
    5.31 +unsigned int create_program(void);
    5.32 +unsigned int create_program_link(unsigned int sdr0, ...);
    5.33 +unsigned int create_program_load(const char *vfile, const char *pfile);
    5.34 +void free_program(unsigned int sdr);
    5.35 +
    5.36 +void attach_shader(unsigned int prog, unsigned int sdr);
    5.37 +int link_program(unsigned int prog);
    5.38 +int bind_program(unsigned int prog);
    5.39 +
    5.40 +int set_uniform_int(unsigned int prog, const char *name, int val);
    5.41 +int set_uniform_float(unsigned int prog, const char *name, float val);
    5.42 +int set_uniform_float2(unsigned int prog, const char *name, float x, float y);
    5.43 +int set_uniform_float3(unsigned int prog, const char *name, float x, float y, float z);
    5.44 +int set_uniform_float4(unsigned int prog, const char *name, float x, float y, float z, float w);
    5.45 +int set_uniform_matrix4(unsigned int prog, const char *name, float *mat);
    5.46 +int set_uniform_matrix4_transposed(unsigned int prog, const char *name, float *mat);
    5.47 +
    5.48 +int get_attrib_loc(unsigned int prog, const char *name);
    5.49 +void set_attrib_float3(int attr_loc, float x, float y, float z);
    5.50 +
    5.51 +#ifdef __cplusplus
    5.52 +}
    5.53 +#endif	/* __cplusplus */
    5.54 +
    5.55 +#endif	/* SDR_H_ */
     6.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     6.2 +++ b/spycam/src/spycam.cc	Tue Mar 08 03:26:01 2016 +0200
     6.3 @@ -0,0 +1,98 @@
     6.4 +#include <GLES2/gl2.h>
     6.5 +#include <gmath/gmath.h>
     6.6 +#include "spycam.h"
     6.7 +#include "sdr.h"
     6.8 +
     6.9 +static unsigned int sdr_prog, tex;
    6.10 +static Mat4 world_matrix, view_matrix, proj_matrix;
    6.11 +static int win_width, win_height;
    6.12 +
    6.13 +bool app_init()
    6.14 +{
    6.15 +	glClearColor(0.2, 0.2, 0.2, 1);
    6.16 +
    6.17 +	if(!(sdr_prog = create_program_load("sdr/vertex.glsl", "sdr/pixel.glsl"))) {
    6.18 +		fprintf(stderr, "failed to load shader program\n");
    6.19 +		return false;
    6.20 +	}
    6.21 +	glUseProgram(sdr_prog);
    6.22 +	glBindAttribLocation(sdr_prog, 0, "a_vertex");
    6.23 +	glBindAttribLocation(sdr_prog, 1, "a_texcoord");
    6.24 +
    6.25 +	unsigned char *pixels = new unsigned char[256 * 256 * 3];
    6.26 +	unsigned char *pptr = pixels;
    6.27 +	for(int i=0; i<256; i++) {
    6.28 +		for(int j=0; j<256; j++) {
    6.29 +			bool chess = ((i >> 4) & 1) == ((j >> 4) & 1);
    6.30 +			*pptr++ = chess ? 255 : 64;
    6.31 +			*pptr++ = 128;
    6.32 +			*pptr++ = chess ? 64 : 255;
    6.33 +		}
    6.34 +	}
    6.35 +
    6.36 +	glGenTextures(1, &tex);
    6.37 +	glBindTexture(GL_TEXTURE_2D, tex);
    6.38 +	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
    6.39 +	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    6.40 +	glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 256, 256, 0, GL_RGB, GL_UNSIGNED_BYTE, pixels);
    6.41 +	glGenerateMipmap(GL_TEXTURE_2D);
    6.42 +	delete [] pixels;
    6.43 +
    6.44 +	return true;
    6.45 +}
    6.46 +
    6.47 +void app_cleanup()
    6.48 +{
    6.49 +}
    6.50 +
    6.51 +void app_draw()
    6.52 +{
    6.53 +	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    6.54 +
    6.55 +	glUseProgram(sdr_prog);
    6.56 +	set_uniform_matrix4(sdr_prog, "world_mat", world_matrix[0]);
    6.57 +	set_uniform_matrix4(sdr_prog, "view_mat", view_matrix[0]);
    6.58 +	set_uniform_matrix4(sdr_prog, "proj_mat", proj_matrix[0]);
    6.59 +
    6.60 +	glBindTexture(GL_TEXTURE_2D, tex);
    6.61 +
    6.62 +	static const float quad_verts[] = {-1, -1, 1, -1, 1, 1, -1, 1};
    6.63 +	static const float quad_texcoords[] = {0, 0, 1, 0, 1, 1, 0, 1};
    6.64 +	static const unsigned int quad_idx[] = {0, 1, 2, 0, 2, 3};
    6.65 +
    6.66 +	glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, quad_verts);
    6.67 +	glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 0, quad_texcoords);
    6.68 +	glEnableVertexAttribArray(0);
    6.69 +	glEnableVertexAttribArray(1);
    6.70 +
    6.71 +	glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, quad_idx);
    6.72 +
    6.73 +	glDisableVertexAttribArray(0);
    6.74 +	glDisableVertexAttribArray(1);
    6.75 +}
    6.76 +
    6.77 +void app_reshape(int x, int y)
    6.78 +{
    6.79 +	win_width = x;
    6.80 +	win_height = y;
    6.81 +	glViewport(0, 0, x, y);
    6.82 +}
    6.83 +
    6.84 +void app_keyboard(int key, bool press)
    6.85 +{
    6.86 +	if(press) {
    6.87 +		switch(key) {
    6.88 +		case 27:
    6.89 +			app_quit();
    6.90 +			break;
    6.91 +		}
    6.92 +	}
    6.93 +}
    6.94 +
    6.95 +void app_mouse_button(int bn, bool press, int x, int y)
    6.96 +{
    6.97 +}
    6.98 +
    6.99 +void app_mouse_motion(int x, int y)
   6.100 +{
   6.101 +}
     7.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     7.2 +++ b/spycam/src/spycam.h	Tue Mar 08 03:26:01 2016 +0200
     7.3 @@ -0,0 +1,15 @@
     7.4 +#ifndef SPYCAM_H_
     7.5 +#define SPYCAM_H_
     7.6 +
     7.7 +bool app_init();
     7.8 +void app_cleanup();
     7.9 +void app_draw();
    7.10 +void app_reshape(int x, int y);
    7.11 +void app_keyboard(int key, bool press);
    7.12 +void app_mouse_button(int bn, bool press, int x, int y);
    7.13 +void app_mouse_motion(int x, int y);
    7.14 +
    7.15 +void app_quit();
    7.16 +void app_redisplay();
    7.17 +
    7.18 +#endif	/* SPYCAM_H_ */