# HG changeset patch # User John Tsiombikas # Date 1457400361 -7200 # Node ID a5755687dd7523f2f9c8394e4de67ea2caf5ac1b initial commit diff -r 000000000000 -r a5755687dd75 .hgignore --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.hgignore Tue Mar 08 03:26:01 2016 +0200 @@ -0,0 +1,4 @@ +\.o$ +\.d$ +\.swp$ +spycam$ diff -r 000000000000 -r a5755687dd75 spycam/Makefile --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/spycam/Makefile Tue Mar 08 03:26:01 2016 +0200 @@ -0,0 +1,19 @@ +src = $(wildcard src/*.cc) +csrc = $(wildcard src/*.c) +obj = $(src:.cc=.o) $(csrc:.c=.o) +bin = spycam + +warn = -pedantic -Wall +opt = -O0 +dbg = -g + +CFLAGS = $(warn) $(opt) $(dbg) +CXXFLAGS = $(warn) $(opt) $(dbg) +LDFLAGS = -lX11 -lEGL -lGLESv2 -lm -lgmath + +$(bin): $(obj) + $(CXX) -o $@ $(obj) $(LDFLAGS) + +.PHONY: clean +clean: + rm -f $(obj) $(bin) diff -r 000000000000 -r a5755687dd75 spycam/src/main.cc --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/spycam/src/main.cc Tue Mar 08 03:26:01 2016 +0200 @@ -0,0 +1,236 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include "spycam.h" + +static void cleanup(); +static bool create_glwin(int xsz, int ysz); +static bool handle_event(XEvent *ev); +static void set_window_title(const char *title); + +static int win_width, win_height; +static bool quit, redraw_pending; +static Display *dpy; +static Window win; +static EGLDisplay egl_dpy; +static EGLContext egl_ctx; +static EGLSurface egl_win; +static Atom xa_wm_proto, xa_del_window; + +int main(int argc, char **argv) +{ + if(!(dpy = XOpenDisplay(0))) { + fprintf(stderr, "failed to connect to the X server.\n"); + return 1; + } + xa_wm_proto = XInternAtom(dpy, "WM_PROTOCOLS", False); + xa_del_window = XInternAtom(dpy, "WM_DELETE_WINDOW", False); + + egl_dpy = eglGetDisplay(dpy); + int egl_ver_major, egl_ver_minor; + if(!eglInitialize(egl_dpy, &egl_ver_major, &egl_ver_minor)) { + fprintf(stderr, "failed to initialize EGL\n"); + return 1; + } + printf("initialized EGL %d.%d\n", egl_ver_major, egl_ver_minor); + + if(!create_glwin(800, 600)) { + cleanup(); + return 1; + } + + if(!app_init()) { + cleanup(); + return 1; + } + + for(;;) { + while(XPending(dpy) || !redraw_pending) { + XEvent ev; + XNextEvent(dpy, &ev); + if(!handle_event(&ev) || quit) { + goto break_main_loop; + } + } + + if(redraw_pending) { + app_draw(); + eglSwapBuffers(egl_dpy, egl_win); + } + } +break_main_loop: + + cleanup(); + return 0; +} + +void app_quit() +{ + quit = true; +} + +void app_redisplay() +{ + redraw_pending = true; +} + +static void cleanup() +{ + if(egl_dpy) { + eglMakeCurrent(egl_dpy, 0, 0, 0); + if(egl_win) + eglDestroySurface(egl_dpy, egl_win); + if(egl_ctx) + eglDestroyContext(egl_dpy, egl_ctx); + eglTerminate(egl_dpy); + } + if(dpy) { + if(win) + XDestroyWindow(dpy, win); + XCloseDisplay(dpy); + } +} + +static bool create_glwin(int xsz, int ysz) +{ + static const int egl_attr[] = { + EGL_SURFACE_TYPE, EGL_WINDOW_BIT, + EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT, + EGL_RED_SIZE, 5, + EGL_GREEN_SIZE, 5, + EGL_BLUE_SIZE, 5, + EGL_DEPTH_SIZE, 16, + EGL_NONE + }; + + int scr = DefaultScreen(dpy); + Window root_win = RootWindow(dpy, scr); + + EGLConfig cfg; + int num_cfg; + if(!eglChooseConfig(egl_dpy, egl_attr, &cfg, 1, &num_cfg)) { + fprintf(stderr, "failed to find matching EGL visual\n"); + return false; + } + int rsize, gsize, bsize, zsize, ssize, vis_id; + eglGetConfigAttrib(egl_dpy, cfg, EGL_RED_SIZE, &rsize); + eglGetConfigAttrib(egl_dpy, cfg, EGL_GREEN_SIZE, &gsize); + eglGetConfigAttrib(egl_dpy, cfg, EGL_BLUE_SIZE, &bsize); + eglGetConfigAttrib(egl_dpy, cfg, EGL_DEPTH_SIZE, &zsize); + eglGetConfigAttrib(egl_dpy, cfg, EGL_STENCIL_SIZE, &ssize); + eglGetConfigAttrib(egl_dpy, cfg, EGL_NATIVE_VISUAL_ID, &vis_id); + printf("got visual %d: %d bpp (%d%d%d), %d zbuffer, %d stencil\n", vis_id, rsize + gsize + bsize, + rsize, gsize, bsize, zsize, ssize); + + int num_vis; + XVisualInfo *vis_info, vis_template; + vis_template.visualid = vis_id; + if(!(vis_info = XGetVisualInfo(dpy, VisualIDMask, &vis_template, &num_vis))) { + fprintf(stderr, "visual id %d is invalid (?!)\n", vis_id); + return false; + } + + XSetWindowAttributes xattr; + xattr.border_pixel = xattr.backing_pixel = BlackPixel(dpy, scr); + xattr.colormap = XCreateColormap(dpy, root_win, vis_info->visual, AllocNone); + unsigned int xattr_mask = CWColormap | CWBorderPixel | CWBackPixel; + + win = XCreateWindow(dpy, root_win, 0, 0, xsz, ysz, 0, vis_info->depth, InputOutput, + vis_info->visual, xattr_mask, &xattr); + if(!win) { + fprintf(stderr, "failed to create window\n"); + XFree(vis_info); + return false; + } + XFree(vis_info); + XSelectInput(dpy, win, ExposureMask | StructureNotifyMask | KeyPressMask | KeyReleaseMask); + + XSetWMProtocols(dpy, win, &xa_del_window, 1); + set_window_title("spycam"); + + eglBindAPI(EGL_OPENGL_ES_API); + + if(!(egl_win = eglCreateWindowSurface(egl_dpy, cfg, win, 0))) { + fprintf(stderr, "failed to create EGL window\n"); + XDestroyWindow(dpy, win); + return false; + } + + static const int ctxattr[] = { EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE }; + if(!(egl_ctx = eglCreateContext(egl_dpy, cfg, EGL_NO_CONTEXT, ctxattr))) { + fprintf(stderr, "failed to create EGL context\n"); + eglDestroySurface(egl_dpy, egl_win); + XDestroyWindow(dpy, win); + return false; + } + eglMakeCurrent(egl_dpy, egl_win, egl_win, egl_ctx); + + XMapWindow(dpy, win); + + eglQuerySurface(dpy, egl_win, EGL_WIDTH, &win_width); + eglQuerySurface(dpy, egl_win, EGL_HEIGHT, &win_height); + app_reshape(win_width, win_height); + + return true; +} + +static bool handle_event(XEvent *ev) +{ + static bool mapped; + + switch(ev->type) { + case Expose: + if(mapped) { + redraw_pending = true; + } + break; + + case MapNotify: + mapped = true; + redraw_pending = true; + break; + + case UnmapNotify: + mapped = false; + redraw_pending = false; + break; + + case ConfigureNotify: + if(win_width != (int)ev->xconfigure.width || win_height != (int)ev->xconfigure.height) { + win_width = ev->xconfigure.width; + win_height = ev->xconfigure.height; + app_reshape(win_width, win_height); + } + break; + + case KeyPress: + case KeyRelease: + app_keyboard(XLookupKeysym(&ev->xkey, 0) & 0xff, ev->type == KeyPress); + break; + + case ClientMessage: + if(ev->xclient.message_type == xa_wm_proto && + (Atom)ev->xclient.data.l[0] == xa_del_window) { + return false; + } + break; + + default: + break; + } + return true; +} + +static void set_window_title(const char *title) +{ + XTextProperty text_prop; + XStringListToTextProperty((char**)&title, 1, &text_prop); + XSetWMName(dpy, win, &text_prop); + XSetWMIconName(dpy, win, &text_prop); + XFree(text_prop.value); +} diff -r 000000000000 -r a5755687dd75 spycam/src/sdr.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/spycam/src/sdr.c Tue Mar 08 03:26:01 2016 +0200 @@ -0,0 +1,407 @@ +#include +#include +#include +#include +#include +#include +#include + +#if defined(unix) || defined(__unix__) +#include +#include +#endif /* unix */ + +#include "sdr.h" + +static const char *sdrtypestr(unsigned int sdrtype); + +unsigned int create_vertex_shader(const char *src) +{ + return create_shader(src, GL_VERTEX_SHADER); +} + +unsigned int create_pixel_shader(const char *src) +{ + return create_shader(src, GL_FRAGMENT_SHADER); +} + +unsigned int create_tessctl_shader(const char *src) +{ +#ifdef GL_TESS_CONTROL_SHADER + return create_shader(src, GL_TESS_CONTROL_SHADER); +#else + return 0; +#endif +} + +unsigned int create_tesseval_shader(const char *src) +{ +#ifdef GL_TESS_EVALUATION_SHADER + return create_shader(src, GL_TESS_EVALUATION_SHADER); +#else + return 0; +#endif +} + +unsigned int create_geometry_shader(const char *src) +{ +#ifdef GL_GEOMETRY_SHADER + return create_shader(src, GL_GEOMETRY_SHADER); +#else + return 0; +#endif +} + +unsigned int create_shader(const char *src, unsigned int sdr_type) +{ + unsigned int sdr; + int success, info_len; + char *info_str = 0; + GLenum err; + + sdr = glCreateShader(sdr_type); + assert(glGetError() == GL_NO_ERROR); + glShaderSource(sdr, 1, &src, 0); + err = glGetError(); + assert(err == GL_NO_ERROR); + glCompileShader(sdr); + assert(glGetError() == GL_NO_ERROR); + + glGetShaderiv(sdr, GL_COMPILE_STATUS, &success); + assert(glGetError() == GL_NO_ERROR); + glGetShaderiv(sdr, GL_INFO_LOG_LENGTH, &info_len); + assert(glGetError() == GL_NO_ERROR); + + if(info_len) { + if((info_str = malloc(info_len + 1))) { + glGetShaderInfoLog(sdr, info_len, 0, info_str); + assert(glGetError() == GL_NO_ERROR); + info_str[info_len] = 0; + } + } + + if(success) { + fprintf(stderr, info_str ? "done: %s\n" : "done\n", info_str); + } else { + fprintf(stderr, info_str ? "failed: %s\n" : "failed\n", info_str); + glDeleteShader(sdr); + sdr = 0; + } + + free(info_str); + return sdr; +} + +void free_shader(unsigned int sdr) +{ + glDeleteShader(sdr); +} + +unsigned int load_vertex_shader(const char *fname) +{ + return load_shader(fname, GL_VERTEX_SHADER); +} + +unsigned int load_pixel_shader(const char *fname) +{ + return load_shader(fname, GL_FRAGMENT_SHADER); +} + +unsigned int load_tessctl_shader(const char *fname) +{ +#ifdef GL_TESS_CONTROL_SHADER + return load_shader(fname, GL_TESS_CONTROL_SHADER); +#else + return 0; +#endif +} + +unsigned int load_tesseval_shader(const char *fname) +{ +#ifdef GL_TESS_EVALUATION_SHADER + return load_shader(fname, GL_TESS_EVALUATION_SHADER); +#else + return 0; +#endif +} + +unsigned int load_geometry_shader(const char *fname) +{ +#ifdef GL_GEOMETRY_SHADER + return load_shader(fname, GL_GEOMETRY_SHADER); +#else + return 0; +#endif +} + +unsigned int load_shader(const char *fname, unsigned int sdr_type) +{ + unsigned int sdr; + size_t filesize; + FILE *fp; + char *src; + + if(!(fp = fopen(fname, "rb"))) { + fprintf(stderr, "failed to open shader %s: %s\n", fname, strerror(errno)); + return 0; + } + + fseek(fp, 0, SEEK_END); + filesize = ftell(fp); + fseek(fp, 0, SEEK_SET); + + if(!(src = malloc(filesize + 1))) { + fclose(fp); + return 0; + } + fread(src, 1, filesize, fp); + src[filesize] = 0; + fclose(fp); + + fprintf(stderr, "compiling %s shader: %s... ", sdrtypestr(sdr_type), fname); + sdr = create_shader(src, sdr_type); + + free(src); + return sdr; +} + + +/* ---- gpu programs ---- */ + +unsigned int create_program(void) +{ + unsigned int prog = glCreateProgram(); + assert(glGetError() == GL_NO_ERROR); + return prog; +} + +unsigned int create_program_link(unsigned int sdr0, ...) +{ + unsigned int prog, sdr; + va_list ap; + + if(!(prog = create_program())) { + return 0; + } + + attach_shader(prog, sdr0); + if(glGetError()) { + return 0; + } + + va_start(ap, sdr0); + while((sdr = va_arg(ap, unsigned int))) { + attach_shader(prog, sdr); + if(glGetError()) { + return 0; + } + } + va_end(ap); + + if(link_program(prog) == -1) { + free_program(prog); + return 0; + } + return prog; +} + +unsigned int create_program_load(const char *vfile, const char *pfile) +{ + unsigned int vs = 0, ps = 0; + + if(vfile && *vfile && !(vs = load_vertex_shader(vfile))) { + return 0; + } + if(pfile && *pfile && !(ps = load_pixel_shader(pfile))) { + return 0; + } + return create_program_link(vs, ps, 0); +} + +void free_program(unsigned int sdr) +{ + glDeleteProgram(sdr); +} + +void attach_shader(unsigned int prog, unsigned int sdr) +{ + int err; + + if(prog && sdr) { + assert(glGetError() == GL_NO_ERROR); + glAttachShader(prog, sdr); + if((err = glGetError()) != GL_NO_ERROR) { + fprintf(stderr, "failed to attach shader %u to program %u (err: 0x%x)\n", sdr, prog, err); + abort(); + } + } +} + +int link_program(unsigned int prog) +{ + int linked, info_len, retval = 0; + char *info_str = 0; + + glLinkProgram(prog); + assert(glGetError() == GL_NO_ERROR); + glGetProgramiv(prog, GL_LINK_STATUS, &linked); + assert(glGetError() == GL_NO_ERROR); + glGetProgramiv(prog, GL_INFO_LOG_LENGTH, &info_len); + assert(glGetError() == GL_NO_ERROR); + + if(info_len) { + if((info_str = malloc(info_len + 1))) { + glGetProgramInfoLog(prog, info_len, 0, info_str); + assert(glGetError() == GL_NO_ERROR); + info_str[info_len] = 0; + } + } + + if(linked) { + fprintf(stderr, info_str ? "linking done: %s\n" : "linking done\n", info_str); + } else { + fprintf(stderr, info_str ? "linking failed: %s\n" : "linking failed\n", info_str); + retval = -1; + } + + free(info_str); + return retval; +} + +int bind_program(unsigned int prog) +{ + GLenum err; + + glUseProgram(prog); + if(prog && (err = glGetError()) != GL_NO_ERROR) { + /* maybe the program is not linked, try linking first */ + if(err == GL_INVALID_OPERATION) { + if(link_program(prog) == -1) { + return -1; + } + glUseProgram(prog); + return glGetError() == GL_NO_ERROR ? 0 : -1; + } + return -1; + } + return 0; +} + +/* ugly but I'm not going to write the same bloody code over and over */ +#define BEGIN_UNIFORM_CODE \ + int loc, curr_prog; \ + glGetIntegerv(GL_CURRENT_PROGRAM, &curr_prog); \ + if((unsigned int)curr_prog != prog && bind_program(prog) == -1) { \ + return -1; \ + } \ + if((loc = glGetUniformLocation(prog, name)) != -1) + +#define END_UNIFORM_CODE \ + if((unsigned int)curr_prog != prog) { \ + bind_program(curr_prog); \ + } \ + return loc == -1 ? -1 : 0 + +int set_uniform_int(unsigned int prog, const char *name, int val) +{ + BEGIN_UNIFORM_CODE { + glUniform1i(loc, val); + } + END_UNIFORM_CODE; +} + +int set_uniform_float(unsigned int prog, const char *name, float val) +{ + BEGIN_UNIFORM_CODE { + glUniform1f(loc, val); + } + END_UNIFORM_CODE; +} + +int set_uniform_float2(unsigned int prog, const char *name, float x, float y) +{ + BEGIN_UNIFORM_CODE { + glUniform2f(loc, x, y); + } + END_UNIFORM_CODE; +} + +int set_uniform_float3(unsigned int prog, const char *name, float x, float y, float z) +{ + BEGIN_UNIFORM_CODE { + glUniform3f(loc, x, y, z); + } + END_UNIFORM_CODE; +} + +int set_uniform_float4(unsigned int prog, const char *name, float x, float y, float z, float w) +{ + BEGIN_UNIFORM_CODE { + glUniform4f(loc, x, y, z, w); + } + END_UNIFORM_CODE; +} + +int set_uniform_matrix4(unsigned int prog, const char *name, float *mat) +{ + BEGIN_UNIFORM_CODE { + glUniformMatrix4fv(loc, 1, GL_FALSE, mat); + } + END_UNIFORM_CODE; +} + +int set_uniform_matrix4_transposed(unsigned int prog, const char *name, float *mat) +{ + BEGIN_UNIFORM_CODE { + glUniformMatrix4fv(loc, 1, GL_TRUE, mat); + } + END_UNIFORM_CODE; +} + +int get_attrib_loc(unsigned int prog, const char *name) +{ + int loc, curr_prog; + + glGetIntegerv(GL_CURRENT_PROGRAM, &curr_prog); + if((unsigned int)curr_prog != prog && bind_program(prog) == -1) { + return -1; + } + + loc = glGetAttribLocation(prog, (char*)name); + + if((unsigned int)curr_prog != prog) { + bind_program(curr_prog); + } + return loc; +} + +void set_attrib_float3(int attr_loc, float x, float y, float z) +{ + glVertexAttrib3f(attr_loc, x, y, z); +} + +static const char *sdrtypestr(unsigned int sdrtype) +{ + switch(sdrtype) { + case GL_VERTEX_SHADER: + return "vertex"; + case GL_FRAGMENT_SHADER: + return "pixel"; +#ifdef GL_TESS_CONTROL_SHADER + case GL_TESS_CONTROL_SHADER: + return "tessellation control"; +#endif +#ifdef GL_TESS_EVALUATION_SHADER + case GL_TESS_EVALUATION_SHADER: + return "tessellation evaluation"; +#endif +#ifdef GL_GEOMETRY_SHADER + case GL_GEOMETRY_SHADER: + return "geometry"; +#endif + + default: + break; + } + return ""; +} diff -r 000000000000 -r a5755687dd75 spycam/src/sdr.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/spycam/src/sdr.h Tue Mar 08 03:26:01 2016 +0200 @@ -0,0 +1,52 @@ +#ifndef SDR_H_ +#define SDR_H_ + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/* ---- shaders ---- */ +unsigned int create_vertex_shader(const char *src); +unsigned int create_pixel_shader(const char *src); +unsigned int create_tessctl_shader(const char *src); +unsigned int create_tesseval_shader(const char *src); +unsigned int create_geometry_shader(const char *src); +unsigned int create_shader(const char *src, unsigned int sdr_type); +void free_shader(unsigned int sdr); + +unsigned int load_vertex_shader(const char *fname); +unsigned int load_pixel_shader(const char *fname); +unsigned int load_tessctl_shader(const char *fname); +unsigned int load_tesseval_shader(const char *fname); +unsigned int load_geometry_shader(const char *fname); +unsigned int load_shader(const char *src, unsigned int sdr_type); + +int add_shader(const char *fname, unsigned int sdr); +int remove_shader(const char *fname); + +/* ---- gpu programs ---- */ +unsigned int create_program(void); +unsigned int create_program_link(unsigned int sdr0, ...); +unsigned int create_program_load(const char *vfile, const char *pfile); +void free_program(unsigned int sdr); + +void attach_shader(unsigned int prog, unsigned int sdr); +int link_program(unsigned int prog); +int bind_program(unsigned int prog); + +int set_uniform_int(unsigned int prog, const char *name, int val); +int set_uniform_float(unsigned int prog, const char *name, float val); +int set_uniform_float2(unsigned int prog, const char *name, float x, float y); +int set_uniform_float3(unsigned int prog, const char *name, float x, float y, float z); +int set_uniform_float4(unsigned int prog, const char *name, float x, float y, float z, float w); +int set_uniform_matrix4(unsigned int prog, const char *name, float *mat); +int set_uniform_matrix4_transposed(unsigned int prog, const char *name, float *mat); + +int get_attrib_loc(unsigned int prog, const char *name); +void set_attrib_float3(int attr_loc, float x, float y, float z); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* SDR_H_ */ diff -r 000000000000 -r a5755687dd75 spycam/src/spycam.cc --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/spycam/src/spycam.cc Tue Mar 08 03:26:01 2016 +0200 @@ -0,0 +1,98 @@ +#include +#include +#include "spycam.h" +#include "sdr.h" + +static unsigned int sdr_prog, tex; +static Mat4 world_matrix, view_matrix, proj_matrix; +static int win_width, win_height; + +bool app_init() +{ + glClearColor(0.2, 0.2, 0.2, 1); + + if(!(sdr_prog = create_program_load("sdr/vertex.glsl", "sdr/pixel.glsl"))) { + fprintf(stderr, "failed to load shader program\n"); + return false; + } + glUseProgram(sdr_prog); + glBindAttribLocation(sdr_prog, 0, "a_vertex"); + glBindAttribLocation(sdr_prog, 1, "a_texcoord"); + + unsigned char *pixels = new unsigned char[256 * 256 * 3]; + unsigned char *pptr = pixels; + for(int i=0; i<256; i++) { + for(int j=0; j<256; j++) { + bool chess = ((i >> 4) & 1) == ((j >> 4) & 1); + *pptr++ = chess ? 255 : 64; + *pptr++ = 128; + *pptr++ = chess ? 64 : 255; + } + } + + glGenTextures(1, &tex); + glBindTexture(GL_TEXTURE_2D, tex); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 256, 256, 0, GL_RGB, GL_UNSIGNED_BYTE, pixels); + glGenerateMipmap(GL_TEXTURE_2D); + delete [] pixels; + + return true; +} + +void app_cleanup() +{ +} + +void app_draw() +{ + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + + glUseProgram(sdr_prog); + set_uniform_matrix4(sdr_prog, "world_mat", world_matrix[0]); + set_uniform_matrix4(sdr_prog, "view_mat", view_matrix[0]); + set_uniform_matrix4(sdr_prog, "proj_mat", proj_matrix[0]); + + glBindTexture(GL_TEXTURE_2D, tex); + + static const float quad_verts[] = {-1, -1, 1, -1, 1, 1, -1, 1}; + static const float quad_texcoords[] = {0, 0, 1, 0, 1, 1, 0, 1}; + static const unsigned int quad_idx[] = {0, 1, 2, 0, 2, 3}; + + glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, quad_verts); + glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 0, quad_texcoords); + glEnableVertexAttribArray(0); + glEnableVertexAttribArray(1); + + glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, quad_idx); + + glDisableVertexAttribArray(0); + glDisableVertexAttribArray(1); +} + +void app_reshape(int x, int y) +{ + win_width = x; + win_height = y; + glViewport(0, 0, x, y); +} + +void app_keyboard(int key, bool press) +{ + if(press) { + switch(key) { + case 27: + app_quit(); + break; + } + } +} + +void app_mouse_button(int bn, bool press, int x, int y) +{ +} + +void app_mouse_motion(int x, int y) +{ +} diff -r 000000000000 -r a5755687dd75 spycam/src/spycam.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/spycam/src/spycam.h Tue Mar 08 03:26:01 2016 +0200 @@ -0,0 +1,15 @@ +#ifndef SPYCAM_H_ +#define SPYCAM_H_ + +bool app_init(); +void app_cleanup(); +void app_draw(); +void app_reshape(int x, int y); +void app_keyboard(int key, bool press); +void app_mouse_button(int bn, bool press, int x, int y); +void app_mouse_motion(int x, int y); + +void app_quit(); +void app_redisplay(); + +#endif /* SPYCAM_H_ */