# HG changeset patch # User John Tsiombikas # Date 1421900392 -7200 # Node ID dc7af0f549b22f0af40738ce7ef94798c155c7fe # Parent 6a3a9840c303d936ef0deb337cf6736ef5799906 VR point sprite shooting test diff -r 6a3a9840c303 -r dc7af0f549b2 Makefile --- a/Makefile Wed Jan 21 11:29:30 2015 +0200 +++ b/Makefile Thu Jan 22 06:19:52 2015 +0200 @@ -2,11 +2,14 @@ obj = $(src:.c=.o) bin = oculus2 -CFLAGS = -pedantic -Wall -g `pkg-config --cflags sdl2` -LDFLAGS = $(libgl) `pkg-config --libs sdl2` -lovr $(libsys) +warn = -pedantic -Wall + +CFLAGS = $(warn) -g `pkg-config --cflags sdl2` +LDFLAGS = $(libgl) `pkg-config --libs sdl2` -lovr $(libsys) -lvmath ifeq ($(shell uname -s), Darwin) libgl = -framework OpenGL -lGLEW + warn += -Wno-deprecated-declarations else libgl = -lGL -lGLU -lGLEW libsys = -lX11 diff -r 6a3a9840c303 -r dc7af0f549b2 sdr/psprite.p.glsl --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sdr/psprite.p.glsl Thu Jan 22 06:19:52 2015 +0200 @@ -0,0 +1,12 @@ +#version 120 + +void main() +{ + vec2 pt = gl_PointCoord.xy * 2.0 - 1.0; + float len = length(pt); + vec2 dir = pt / len; + float angle = atan(dir.y, dir.x); + + float alpha = 1.0 - smoothstep(0.8, 0.9, len + abs(sin(angle * 8.0)) * 0.1); + gl_FragColor = vec4(1.0, 1.0, 1.0, alpha); +} diff -r 6a3a9840c303 -r dc7af0f549b2 sdr/psprite.v.glsl --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sdr/psprite.v.glsl Thu Jan 22 06:19:52 2015 +0200 @@ -0,0 +1,22 @@ +uniform vec2 viewport; + +void main() +{ + const float psize = 1.0; + + vec4 ppos = gl_ModelViewProjectionMatrix * gl_Vertex; + gl_Position = ppos; + + float vs_z = (gl_ModelViewMatrix * gl_Vertex).z; + vec4 p0 = gl_ProjectionMatrix * vec4(0.0, 0.0, vs_z, 1.0); + vec4 p1 = gl_ProjectionMatrix * vec4(psize, 0.0, vs_z, 1.0); + + p0.xyz /= p0.w; + p1.xyz /= p1.w; + + p0.xy = (p0.xy * vec2(0.5, 0.5) + vec2(0.5, 0.5)) * viewport; + p1.xy = (p1.xy * vec2(0.5, 0.5) + vec2(0.5, 0.5)) * viewport; + + float sz = length(p1.xy - p0.xy); + gl_PointSize = sz; +} diff -r 6a3a9840c303 -r dc7af0f549b2 src/main.c --- a/src/main.c Wed Jan 21 11:29:30 2015 +0200 +++ b/src/main.c Thu Jan 22 06:19:52 2015 +0200 @@ -1,11 +1,3 @@ -/* Very simple OculusSDK OpenGL usage example. - * - * Uses SDL2 (www.libsdl.org) for event handling and OpenGL context management. - * Uses GLEW (glew.sourceforge.net) for OpenGL extension wrangling. - * - * Author: John Tsiombikas - * This code is in the public domain. Do whatever you like with it. - */ #include #include #include @@ -24,11 +16,16 @@ #include #include +#include "projectile.h" + +#define GUN_Y 1.5 int init(void); +int init_rift(void); void cleanup(void); void toggle_hmd_fullscreen(void); void display(void); +void display_rift(void); void draw_scene(void); void draw_box(float xsz, float ysz, float zsz, float norm_sign); void update_rtarg(int width, int height); @@ -38,6 +35,7 @@ unsigned int next_pow2(unsigned int x); void quat_to_matrix(const float *quat, float *mat); unsigned int gen_chess_tex(float r0, float g0, float b0, float r1, float g1, float b1); +int parse_args(int argc, char **argv); /* forward declaration to avoid including non-public headers of libovr */ OVR_EXPORT void ovrhmd_EnableHSWDisplaySDKRender(ovrHmd hmd, ovrBool enable); @@ -50,6 +48,7 @@ static int fb_width, fb_height; static int fb_tex_width, fb_tex_height; +static int use_rift = 1; static ovrHmd hmd; static ovrSizei eyeres[2]; static ovrEyeRenderDesc eye_rdesc[2]; @@ -60,9 +59,16 @@ static unsigned int chess_tex; +static float cam_theta, cam_phi; + int main(int argc, char **argv) { + unsigned int msec, prev_frame_msec; + + if(parse_args(argc, argv) == -1) { + return 1; + } if(init() == -1) { return 1; } @@ -74,7 +80,16 @@ goto done; } } - display(); + + msec = SDL_GetTicks(); + update_shots((msec - prev_frame_msec) / 1000.0); + prev_frame_msec = msec; + + if(use_rift) { + display_rift(); + } else { + display(); + } } done: @@ -85,11 +100,13 @@ int init(void) { - int i, x, y; + int x, y; unsigned int flags; - /* libovr must be initialized before we create the OpenGL context */ - ovr_Initialize(); + if(use_rift) { + /* libovr must be initialized before we create the OpenGL context */ + ovr_Initialize(); + } SDL_Init(SDL_INIT_VIDEO | SDL_INIT_TIMER); @@ -106,6 +123,31 @@ glewInit(); + if(use_rift && init_rift() == -1) { + return -1; + } + + if(init_shots() == -1) { + return -1; + } + + glEnable(GL_DEPTH_TEST); + glEnable(GL_CULL_FACE); + glEnable(GL_LIGHTING); + glEnable(GL_LIGHT0); + glEnable(GL_LIGHT1); + glEnable(GL_NORMALIZE); + + glClearColor(0.1, 0.1, 0.1, 1); + + chess_tex = gen_chess_tex(1.0, 0.7, 0.4, 0.4, 0.7, 1.0); + return 0; +} + +int init_rift(void) +{ + int i; + if(!(hmd = ovrHmd_Create(0))) { fprintf(stderr, "failed to open Oculus HMD, falling back to virtual debug HMD\n"); if(!(hmd = ovrHmd_CreateDebug(ovrHmd_DK2))) { @@ -192,26 +234,17 @@ /* disable the retarded "health and safety warning" */ ovrhmd_EnableHSWDisplaySDKRender(hmd, 0); - - glEnable(GL_DEPTH_TEST); - glEnable(GL_CULL_FACE); - glEnable(GL_LIGHTING); - glEnable(GL_LIGHT0); - glEnable(GL_LIGHT1); - glEnable(GL_NORMALIZE); - - glClearColor(0.1, 0.1, 0.1, 1); - - chess_tex = gen_chess_tex(1.0, 0.7, 0.4, 0.4, 0.7, 1.0); return 0; } void cleanup(void) { - if(hmd) { - ovrHmd_Destroy(hmd); + if(use_rift) { + if(hmd) { + ovrHmd_Destroy(hmd); + } + ovr_Shutdown(); } - ovr_Shutdown(); SDL_Quit(); } @@ -226,18 +259,22 @@ * to the rift's part of the desktop before going fullscreen */ SDL_GetWindowPosition(win, &prev_x, &prev_y); - SDL_SetWindowPosition(win, hmd->WindowsPos.x, hmd->WindowsPos.y); + if(use_rift) { + SDL_SetWindowPosition(win, hmd->WindowsPos.x, hmd->WindowsPos.y); + } SDL_SetWindowFullscreen(win, SDL_WINDOW_FULLSCREEN_DESKTOP); #ifdef OVR_OS_LINUX - /* on linux for now we have to deal with screen rotation during rendering. The docs are promoting - * not rotating the DK2 screen globally - */ - glcfg.OGL.Header.BackBufferSize.w = hmd->Resolution.h; - glcfg.OGL.Header.BackBufferSize.h = hmd->Resolution.w; + if(use_rift) { + /* on linux for now we have to deal with screen rotation during rendering. The docs are promoting + * not rotating the DK2 screen globally + */ + glcfg.OGL.Header.BackBufferSize.w = hmd->Resolution.h; + glcfg.OGL.Header.BackBufferSize.h = hmd->Resolution.w; - distort_caps |= ovrDistortionCap_LinuxDevFullscreen; - ovrHmd_ConfigureRendering(hmd, &glcfg.Config, distort_caps, hmd->DefaultEyeFov, eye_rdesc); + distort_caps |= ovrDistortionCap_LinuxDevFullscreen; + ovrHmd_ConfigureRendering(hmd, &glcfg.Config, distort_caps, hmd->DefaultEyeFov, eye_rdesc); + } #endif } else { /* return to windowed mode and move the window back to its original position */ @@ -245,16 +282,38 @@ SDL_SetWindowPosition(win, prev_x, prev_y); #ifdef OVR_OS_LINUX - glcfg.OGL.Header.BackBufferSize = hmd->Resolution; + if(use_rift) { + glcfg.OGL.Header.BackBufferSize = hmd->Resolution; - distort_caps &= ~ovrDistortionCap_LinuxDevFullscreen; - ovrHmd_ConfigureRendering(hmd, &glcfg.Config, distort_caps, hmd->DefaultEyeFov, eye_rdesc); + distort_caps &= ~ovrDistortionCap_LinuxDevFullscreen; + ovrHmd_ConfigureRendering(hmd, &glcfg.Config, distort_caps, hmd->DefaultEyeFov, eye_rdesc); + } #endif } } void display(void) { + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + gluPerspective(50.0, (float)win_width / (float)win_height, 0.5, 500.0); + + glMatrixMode(GL_MODELVIEW); + glLoadIdentity(); + glRotatef(cam_phi, 1, 0, 0); + glRotatef(cam_theta, 0, 1, 0); + glTranslatef(0, -1.6, 0); /* player height */ + + draw_scene(); + + SDL_GL_SwapWindow(win); + assert(glGetError() == GL_NO_ERROR); +} + +void display_rift(void) +{ int i; ovrMatrix4f proj; ovrPosef pose[2]; @@ -330,6 +389,8 @@ { win_width = x; win_height = y; + + glViewport(0, 0, x, y); } void draw_scene(void) @@ -390,6 +451,33 @@ glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, col); draw_box(0.05, 1.2, 6, 1.0); draw_box(6, 1.2, 0.05, 1.0); + + /* draw laser sight */ + glPushMatrix(); + glTranslatef(0, GUN_Y, 0); + glRotatef(-cam_theta, 0, 1, 0); + glRotatef(-cam_phi, 1, 0, 0); + + glPushAttrib(GL_ENABLE_BIT); + glDisable(GL_LIGHTING); + glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + + glDepthMask(0); + glLineWidth(3.0); + + glBegin(GL_LINES); + glColor4f(1.0, 0.2, 0.15, 0.4); + glVertex3f(0, 0, 0); + glVertex3f(0, 0, -100.0); + glEnd(); + glLineWidth(1.0); + + glPopAttrib(); + + glPopMatrix(); + + draw_shots(); } void draw_box(float xsz, float ysz, float zsz, float norm_sign) @@ -486,6 +574,20 @@ printf("created render target: %dx%d (texture size: %dx%d)\n", width, height, fb_tex_width, fb_tex_height); } +void fire(void) +{ + vec3_t pos = {0, GUN_Y, 0}; + vec3_t dir; + float theta = DEG_TO_RAD(cam_theta); + float phi = DEG_TO_RAD(cam_phi); + + dir.x = -sin(-theta) * cos(phi); + dir.y = -sin(phi); + dir.z = -cos(-theta) * cos(phi); + + shoot(pos, v3_scale(dir, 10.0)); +} + int handle_event(SDL_Event *ev) { switch(ev->type) { @@ -502,6 +604,34 @@ case SDL_WINDOWEVENT: if(ev->window.event == SDL_WINDOWEVENT_RESIZED) { reshape(ev->window.data1, ev->window.data2); + } else if(ev->window.event == SDL_WINDOWEVENT_SHOWN) { + int xsz, ysz; + SDL_GetWindowSize(win, &xsz, &ysz); + reshape(xsz, ysz); + } + break; + + case SDL_MOUSEBUTTONDOWN: + if(ev->button.button == SDL_BUTTON_LEFT) { + fire(); + } + break; + + case SDL_MOUSEMOTION: + { + static int prev_x, prev_y; + int dx = ev->motion.x - prev_x; + int dy = ev->motion.y - prev_y; + prev_x = ev->motion.x; + prev_y = ev->motion.y; + + if(ev->motion.state & SDL_BUTTON_RMASK) { + cam_theta += dx * 0.5; + cam_phi += dy * 0.5; + + if(cam_phi < -90) cam_phi = -90; + if(cam_phi > 90) cam_phi = 90; + } } break; @@ -628,3 +758,23 @@ return tex; } + +int parse_args(int argc, char **argv) +{ + int i; + + for(i=1; i +#include +#include "projectile.h" +#include "sdr.h" + +#define MAX_DIST_SQ (100.0 * 100.0) + +struct projectile { + vec3_t pos, vel; + struct projectile *next; +}; + +static struct projectile *plist, *ptail; +static unsigned int prog; + +int init_shots(void) +{ + if(!(prog = create_program_load("sdr/psprite.v.glsl", "sdr/psprite.p.glsl"))) { + return -1; + } + return 0; +} + +void shoot(vec3_t orig, vec3_t dir) +{ + struct projectile *p; + + if(!(p = malloc(sizeof *p))) { + return; + } + p->pos = orig; + p->vel = dir; + p->next = 0; + + if(plist) { + ptail->next = p; + ptail = p; + } else { + plist = ptail = p; + } +} + +void update_shots(float dt) +{ + struct projectile dummy, *pp; + + dummy.next = plist; + pp = &dummy; + + while(pp->next) { + struct projectile *p = pp->next; + + p->pos = v3_add(p->pos, v3_scale(p->vel, dt)); + + if(v3_length_sq(p->pos) > MAX_DIST_SQ) { + void *tmp = p; + pp->next = p->next; + free(tmp); + } else { + pp = pp->next; + } + } + + plist = dummy.next; +} + +void draw_shots(void) +{ + int vp[4]; + struct projectile *p = plist; + + glPushAttrib(GL_ENABLE_BIT); + + glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + + glDepthMask(0); + + glEnable(GL_POINT_SPRITE); + glEnable(GL_PROGRAM_POINT_SIZE); + glUseProgram(prog); + + glGetIntegerv(GL_VIEWPORT, vp); + if(set_uniform_float2(prog, "viewport", vp[2], vp[3]) == -1) { + fprintf(stderr, "failed to set viewport\n"); + } + + glBegin(GL_POINTS); + + while(p) { + glVertex3f(p->pos.x, p->pos.y, p->pos.z); + p = p->next; + } + + glEnd(); + + glDepthMask(1); + + glUseProgram(0); + glPopAttrib(); + + + glDisable(GL_LIGHTING); + glBegin(GL_LINES); + glColor3f(0, 1, 0); + p = plist; + while(p) { + float x0 = p->pos.x - 0.5; + float y0 = p->pos.y - 0.5; + float x1 = p->pos.x + 0.5; + float y1 = p->pos.y + 0.5; + glVertex3f(x0, y0, p->pos.z); + glVertex3f(x1, y0, p->pos.z); + glVertex3f(x1, y0, p->pos.z); + glVertex3f(x1, y1, p->pos.z); + glVertex3f(x1, y1, p->pos.z); + glVertex3f(x0, y1, p->pos.z); + glVertex3f(x0, y1, p->pos.z); + glVertex3f(x0, y0, p->pos.z); + p = p->next; + } + glEnd(); + glEnable(GL_LIGHTING); +} diff -r 6a3a9840c303 -r dc7af0f549b2 src/projectile.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/projectile.h Thu Jan 22 06:19:52 2015 +0200 @@ -0,0 +1,13 @@ +#ifndef PROJECTILE_H_ +#define PROJECTILE_H_ + +#include + +int init_shots(void); + +void shoot(vec3_t orig, vec3_t dir); + +void update_shots(float dt); +void draw_shots(void); + +#endif /* PROJECTILE_H_ */ diff -r 6a3a9840c303 -r dc7af0f549b2 src/sdr.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/sdr.c Thu Jan 22 06:19:52 2015 +0200 @@ -0,0 +1,427 @@ +/* +Printblobs - halftoning display hack +Copyright (C) 2013 John Tsiombikas + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . +*/ +#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) +{ + return create_shader(src, GL_TESS_CONTROL_SHADER); +} + +unsigned int create_tesseval_shader(const char *src) +{ + return create_shader(src, GL_TESS_EVALUATION_SHADER); +} + +unsigned int create_geometry_shader(const char *src) +{ + return create_shader(src, GL_GEOMETRY_SHADER); +} + +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); + } + } + + 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) +{ + return load_shader(fname, GL_TESS_CONTROL_SHADER); +} + +unsigned int load_tesseval_shader(const char *fname) +{ + return load_shader(fname, GL_TESS_EVALUATION_SHADER); +} + +unsigned int load_geometry_shader(const char *fname) +{ + return load_shader(fname, GL_GEOMETRY_SHADER); +} + +unsigned int load_shader(const char *fname, unsigned int sdr_type) +{ +#if defined(unix) || defined(__unix__) + struct stat st; +#endif + unsigned int sdr; + size_t filesize; + FILE *fp; + char *src; + + if(!(fp = fopen(fname, "r"))) { + fprintf(stderr, "failed to open shader %s: %s\n", fname, strerror(errno)); + return 0; + } + +#if defined(unix) || defined(__unix__) + fstat(fileno(fp), &st); + filesize = st.st_size; +#else + fseek(fp, 0, SEEK_END); + filesize = ftell(fp); + fseek(fp, 0, SEEK_SET); +#endif /* unix */ + + 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; +} + + +unsigned int get_vertex_shader(const char *fname) +{ + return get_shader(fname, GL_VERTEX_SHADER); +} + +unsigned int get_pixel_shader(const char *fname) +{ + return get_shader(fname, GL_FRAGMENT_SHADER); +} + +unsigned int get_tessctl_shader(const char *fname) +{ + return get_shader(fname, GL_TESS_CONTROL_SHADER); +} + +unsigned int get_tesseval_shader(const char *fname) +{ + return get_shader(fname, GL_TESS_EVALUATION_SHADER); +} + +unsigned int get_geometry_shader(const char *fname) +{ + return get_shader(fname, GL_GEOMETRY_SHADER); +} + +unsigned int get_shader(const char *fname, unsigned int sdr_type) +{ + unsigned int sdr; + if(!(sdr = load_shader(fname, sdr_type))) { + return 0; + } + 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 = get_vertex_shader(vfile))) { + return 0; + } + if(pfile && *pfile && !(ps = get_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) +{ + glAttachShader(prog, sdr); + assert(glGetError() == GL_NO_ERROR); +} + +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); + } + } + + 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"; + case GL_TESS_CONTROL_SHADER: + return "tessellation control"; + case GL_TESS_EVALUATION_SHADER: + return "tessellation evaluation"; + case GL_GEOMETRY_SHADER: + return "geometry"; + + default: + break; + } + return ""; +} diff -r 6a3a9840c303 -r dc7af0f549b2 src/sdr.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/sdr.h Thu Jan 22 06:19:52 2015 +0200 @@ -0,0 +1,76 @@ +/* +Printblobs - halftoning display hack +Copyright (C) 2013 John Tsiombikas + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . +*/ +#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); + +unsigned int get_vertex_shader(const char *fname); +unsigned int get_pixel_shader(const char *fname); +unsigned int get_tessctl_shader(const char *fname); +unsigned int get_tesseval_shader(const char *fname); +unsigned int get_geometry_shader(const char *fname); +unsigned int get_shader(const char *fname, 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_ */