From 89df915930177f3bc5f71095562c6e15074be220 Mon Sep 17 00:00:00 2001 From: John Tsiombikas Date: Sun, 12 Aug 2018 07:50:46 +0300 Subject: [PATCH 1/1] going to sleep --- sdr/field.p.glsl | 12 ++ sdr/field.tc.glsl | 20 ++ sdr/field.te.glsl | 22 +++ sdr/field.v.glsl | 8 + src/gamescr.cc | 182 +++++++++++++++-- src/main.cc | 47 +++++ src/sdr.c | 562 +++++++++++++++++++++++++++++++++++++++++++++++++++++ src/sdr.h | 68 +++++++ 8 files changed, 909 insertions(+), 12 deletions(-) create mode 100644 sdr/field.p.glsl create mode 100644 sdr/field.tc.glsl create mode 100644 sdr/field.te.glsl create mode 100644 sdr/field.v.glsl create mode 100644 src/sdr.c create mode 100644 src/sdr.h diff --git a/sdr/field.p.glsl b/sdr/field.p.glsl new file mode 100644 index 0000000..b8888c9 --- /dev/null +++ b/sdr/field.p.glsl @@ -0,0 +1,12 @@ +#version 410 compatibility + +uniform sampler2D gvis_tex, field_tex; + +void main() +{ + vec4 gridcol = texture2D(gvis_tex, gl_TexCoord[0].st); + float field = -texture2D(field_tex, gl_TexCoord[1].st).x; + + gl_FragColor.rgb = gridcol.rgb + vec3(field, field, field); + gl_FragColor.a = 1.0; +} diff --git a/sdr/field.tc.glsl b/sdr/field.tc.glsl new file mode 100644 index 0000000..71d6560 --- /dev/null +++ b/sdr/field.tc.glsl @@ -0,0 +1,20 @@ +#version 410 compatibility + +layout(vertices = 4) out; + +uniform int tess_level; + +void main() +{ + gl_out[gl_InvocationID].gl_Position = gl_in[gl_InvocationID].gl_Position; + gl_out[gl_InvocationID].gl_TexCoord[0] = gl_in[gl_InvocationID].gl_TexCoord[0]; + gl_out[gl_InvocationID].gl_TexCoord[1] = gl_in[gl_InvocationID].gl_TexCoord[1]; + + gl_TessLevelInner[0] = tess_level; + gl_TessLevelInner[1] = tess_level; + + gl_TessLevelOuter[0] = tess_level; + gl_TessLevelOuter[1] = tess_level; + gl_TessLevelOuter[2] = tess_level; + gl_TessLevelOuter[3] = tess_level; +} diff --git a/sdr/field.te.glsl b/sdr/field.te.glsl new file mode 100644 index 0000000..cb01515 --- /dev/null +++ b/sdr/field.te.glsl @@ -0,0 +1,22 @@ +#version 410 compatibility + +layout(quads, ccw) in; + +void main() +{ + vec4 v1 = mix(gl_in[0].gl_Position, gl_in[1].gl_Position, gl_TessCoord.x); + vec4 v2 = mix(gl_in[3].gl_Position, gl_in[2].gl_Position, gl_TessCoord.x); + vec4 pos = mix(v1, v2, gl_TessCoord.y); + + vec4 top0 = mix(gl_in[0].gl_TexCoord[0], gl_in[1].gl_TexCoord[0], gl_TessCoord.x); + vec4 bot0 = mix(gl_in[3].gl_TexCoord[0], gl_in[2].gl_TexCoord[0], gl_TessCoord.x); + vec4 res0 = mix(top0, bot0, gl_TessCoord.y); + + vec4 top1 = mix(gl_in[0].gl_TexCoord[1], gl_in[1].gl_TexCoord[1], gl_TessCoord.x); + vec4 bot1 = mix(gl_in[3].gl_TexCoord[1], gl_in[2].gl_TexCoord[1], gl_TessCoord.x); + vec4 res1 = mix(top1, bot1, gl_TessCoord.y); + + gl_Position = gl_ModelViewProjectionMatrix * pos; + gl_TexCoord[0] = res0; + gl_TexCoord[1] = res1; +} diff --git a/sdr/field.v.glsl b/sdr/field.v.glsl new file mode 100644 index 0000000..26760af --- /dev/null +++ b/sdr/field.v.glsl @@ -0,0 +1,8 @@ +#version 410 compatibility + +void main() +{ + gl_Position = gl_Vertex; + gl_TexCoord[0] = gl_MultiTexCoord0; + gl_TexCoord[1] = gl_MultiTexCoord1; +} diff --git a/src/gamescr.cc b/src/gamescr.cc index 26afe42..d51c16a 100644 --- a/src/gamescr.cc +++ b/src/gamescr.cc @@ -1,9 +1,11 @@ +#include #include #include #include "game.h" #include "screen.h" #include "opengl.h" #include "texture.h" +#include "sdr.h" /* NOTES: * - whistle hhgg music @@ -12,6 +14,7 @@ */ struct Particle { + float radius; float mass; Vec2 pos; Vec2 vel; @@ -24,61 +27,181 @@ struct Emitter { float angle, spread; }; +struct Rect { + int x, y; + int width, height; +}; #define SIM_DT 0.016 -#define GRID_SIZE 4096 +#define GRID_SIZE 2048 #define GRID_BITS 12 #define GRID_X(idx) (((idx) >> GRID_BITS) & (GRID_SIZE - 1)) #define GRID_Y(idx) ((idx) & (GRID_SIZE - 1)) +#define GRID_DELTA ((float)FIELD_SIZE / (float)GRID_SIZE) #define FIELD_SIZE 2048 #define MIN_CAM_DIST 1.0f #define MAX_CAM_DIST 350.0f +#define MASS_TO_RAD(m) log((m) + 1.0) + +#define CONTRIB_THRES 0.005 +#define CONTRIB_RANGE(m) sqrt((m) / CONTRIB_THRES) + static int pos_to_grid(float x, float y); +static Vec2 grid_to_pos(int gx, int gy); static float grid[GRID_SIZE * GRID_SIZE]; static Particle grid_part[GRID_SIZE * GRID_SIZE]; +static Texture *grid_tex; -static std::vector emitters; +static std::vector emitters; -static Texture *grid_tex; +static Texture *gvis_tex; // texture tile for visualizing a grid +static unsigned int field_sdr; static float cam_theta; static float cam_dist = 100.0f; static Vec2 *targ_pos; static Mat4 view_matrix, proj_matrix; +// emitter placement data (filled by event handlers, completed in update) +static bool emit_place_pending; +static Vec2 emit_place_pos; + bool GameScreen::init() { grid_tex = new Texture; - if(!grid_tex->load("data/purple_grid.png")) { + grid_tex->create(GRID_SIZE, GRID_SIZE, TEX_2D, GL_LUMINANCE32F_ARB); + grid_tex->set_anisotropy(glcaps.max_aniso); + + gvis_tex = new Texture; + if(!gvis_tex->load("data/purple_grid.png")) { return false; } - grid_tex->set_anisotropy(glcaps.max_aniso); + gvis_tex->set_anisotropy(glcaps.max_aniso); + + unsigned int vsdr, tcsdr, tesdr, psdr; + + if(!(vsdr = load_vertex_shader("sdr/field.v.glsl")) || + !(tcsdr = load_tessctl_shader("sdr/field.tc.glsl")) || + !(tesdr = load_tesseval_shader("sdr/field.te.glsl")) || + !(psdr = load_pixel_shader("sdr/field.p.glsl"))) { + return false; + } + + if(!(field_sdr = create_program_link(vsdr, tcsdr, tesdr, psdr, 0))) { + return false; + } + set_uniform_int(field_sdr, "gvis_tex", 0); + set_uniform_int(field_sdr, "field_tex", 1); + set_uniform_int(field_sdr, "tess_level", 2); + + // XXX DBG + emit_place_pos = Vec2(0, 0); + emit_place_pending = true; return true; } void GameScreen::destroy() { - delete grid_tex; + delete gvis_tex; +} + +static void calc_contrib_bounds(const Emitter *em, Rect *rect) +{ + int gidx = pos_to_grid(em->pos.x, em->pos.y); + int gx = GRID_X(gidx); + int gy = GRID_Y(gidx); + int maxrange = (int)ceil(CONTRIB_RANGE(em->mass)); + + int sx = gx - maxrange; + int sy = gy - maxrange; + int ex = gx + maxrange; + int ey = gy + maxrange; + + if(ex > GRID_SIZE) ex = GRID_SIZE; + if(ey > GRID_SIZE) ey = GRID_SIZE; + + rect->x = sx < 0 ? 0 : sx; + rect->y = sy < 0 ? 0 : sy; + rect->width = ex - sx; + rect->height = ey - sy; } static void simstep() { + // calculate gravitational field - assume field within radius constant: m / r^2 + + // first clear the field, and then add contributions + memset(grid, 0, sizeof grid); + + // contribution of emitters + int num_emitters = emitters.size(); + for(int i=0; imass); + + float *gptr = grid + cbox.y * GRID_SIZE + cbox.x; + Vec2 startpos = grid_to_pos(cbox.x, cbox.y); + + for(int y=0; ypos; + float dsq = dot(dir, dir); + float radsq = emradius * emradius; + if(dsq < radsq) { + dsq = radsq; + } + + gptr[x] -= em->mass / dsq; + } + + startpos.y += GRID_DELTA; + gptr += GRID_SIZE; + } + } + + // update texture + assert(glGetError() == GL_NO_ERROR); + grid_tex->bind(); + glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, GRID_SIZE, GRID_SIZE, GL_LUMINANCE, + GL_FLOAT, grid); + assert(glGetError() == GL_NO_ERROR); } static void update() { - static float interval; + if(emit_place_pending) { + emit_place_pending = false; + Emitter *em = new Emitter; + em->pos = emit_place_pos; + em->mass = 100; + em->rate = 1; + em->chunk = 0.05; + em->angle = -1; + em->spread = 0; + emitters.push_back(em); + + Rect cbox; + calc_contrib_bounds(em, &cbox); + printf("bounds: %d,%d %dx%d\n", cbox.x, cbox.y, cbox.width, cbox.height); + } + // update simulation + static float interval; interval += frame_dt; if(interval >= SIM_DT) { interval -= SIM_DT; simstep(); + assert(glGetError() == GL_NO_ERROR); } // update projection matrix @@ -115,7 +238,10 @@ void GameScreen::draw() glDisable(GL_CULL_FACE); glEnable(GL_TEXTURE_2D); - bind_texture(grid_tex); + bind_texture(gvis_tex, 0); + bind_texture(grid_tex, 1); + + glUseProgram(field_sdr); float maxu = FIELD_SIZE / 32.0f; float maxv = FIELD_SIZE / 32.0f; @@ -123,16 +249,26 @@ void GameScreen::draw() glBegin(GL_QUADS); glColor3f(1, 1, 1); - glTexCoord2f(0, 0); + + glMultiTexCoord2f(0, 0, 0); + glMultiTexCoord2f(1, 0, 0); glVertex3f(-hsz, 0, -hsz); - glTexCoord2f(maxu, 0); + + glMultiTexCoord2f(0, maxu, 0); + glMultiTexCoord2f(1, 1, 0); glVertex3f(hsz, 0, -hsz); - glTexCoord2f(maxu, maxv); + + glMultiTexCoord2f(0, maxu, maxv); + glMultiTexCoord2f(1, 1, 1); glVertex3f(hsz, 0, hsz); - glTexCoord2f(0, maxv); + + glMultiTexCoord2f(0, 0, maxv); + glMultiTexCoord2f(1, 0, 1); glVertex3f(-hsz, 0, hsz); glEnd(); + glUseProgram(0); + glPopAttrib(); } @@ -182,3 +318,25 @@ void GameScreen::mwheel(int dir, int x, int y) if(cam_dist <= MIN_CAM_DIST) cam_dist = MIN_CAM_DIST; if(cam_dist > MAX_CAM_DIST) cam_dist = MAX_CAM_DIST; } + + +static int pos_to_grid(float x, float y) +{ + int gx = ((x / (float)FIELD_SIZE) + 0.5f) * (float)GRID_SIZE; + int gy = ((y / (float)FIELD_SIZE) + 0.5f) * (float)GRID_SIZE; + + if(gx < 0) gx = 0; + if(gx >= GRID_SIZE) gx = GRID_SIZE - 1; + if(gy < 0) gy = 0; + if(gy >= GRID_SIZE) gy = GRID_SIZE - 1; + + return (gx << GRID_BITS) | gy; +} + +static Vec2 grid_to_pos(int gx, int gy) +{ + float x = (((float)gx / (float)GRID_SIZE) - 0.5f) * (float)FIELD_SIZE; + float y = (((float)gy / (float)GRID_SIZE) - 0.5f) * (float)FIELD_SIZE; + + return Vec2(x, y); +} diff --git a/src/main.cc b/src/main.cc index 1ee34ad..ca23fbc 100644 --- a/src/main.cc +++ b/src/main.cc @@ -1,11 +1,14 @@ #include #include #include +#include #include #include "game.h" #define KEYST_SZ 65536 / 32 +void draw_text(float x, float y, float r, float g, float b, const char *fmt, ...); + static void display(); static void idle(); static void reshape(int x, int y); @@ -74,12 +77,56 @@ unsigned int game_modkeys() return modkeys; } +void draw_text(float x, float y, float r, float g, float b, const char *fmt, ...) +{ + char buf[256], *text = buf; + va_list ap; + + va_start(ap, fmt); + vsprintf(buf, fmt, ap); + va_end(ap); + + glMatrixMode(GL_MODELVIEW); + glPushMatrix(); + glLoadIdentity(); + glMatrixMode(GL_PROJECTION); + glPushMatrix(); + glLoadIdentity(); + glOrtho(0, win_width, 0, win_height, -1, 1); + + glDisable(GL_LIGHTING); + + glRasterPos2f(1, 1); + glColor3f(r, g, b); + while(*text) { + glutBitmapCharacter(GLUT_BITMAP_HELVETICA_18, *text++); + } + + glEnable(GL_LIGHTING); + + glPopMatrix(); + glMatrixMode(GL_MODELVIEW); + glPopMatrix(); +} + static void display() { frame_time = glutGet(GLUT_ELAPSED_TIME); frame_dt = (frame_time - prev_time) / 1000.0f; game_draw(); + + + static long frames, fps, prev_fps_upd; + draw_text(1, 1, 1, 1, 0, "fps: %ld", fps); + + if(frame_time - prev_fps_upd >= 1000) { + fps = frames; + frames = 0; + prev_fps_upd = frame_time; + } + frames++; + glutSwapBuffers(); } diff --git a/src/sdr.c b/src/sdr.c new file mode 100644 index 0000000..0152a6e --- /dev/null +++ b/src/sdr.c @@ -0,0 +1,562 @@ +#include +#include +#include +#include +#include +#include +#include "opengl.h" + +#if defined(unix) || defined(__unix__) +#include +#include +#endif /* unix */ + +#include "sdr.h" + +static const char *sdrtypestr(unsigned int sdrtype); +static int sdrtypeidx(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; + const char *src_str[3], *header, *footer; + int src_str_count = 0; + GLenum err; + + if((header = get_shader_header(sdr_type))) { + src_str[src_str_count++] = header; + } + src_str[src_str_count++] = src; + if((footer = get_shader_footer(sdr_type))) { + src_str[src_str_count++] = footer; + } + + sdr = glCreateShader(sdr_type); + assert(glGetError() == GL_NO_ERROR); + glShaderSource(sdr, src_str_count, src_str, 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 get_uniform_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 = glGetUniformLocation(prog, name); + if((unsigned int)curr_prog != prog) { + bind_program(curr_prog); + } + return loc; +} + +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, const 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, const 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); +} + +/* ---- shader composition ---- */ +struct string { + char *text; + int len; +}; + +#define NUM_SHADER_TYPES 5 +static struct string header[NUM_SHADER_TYPES]; +static struct string footer[NUM_SHADER_TYPES]; + +static void clear_string(struct string *str) +{ + free(str->text); + str->text = 0; + str->len = 0; +} + +static void append_string(struct string *str, const char *s) +{ + int len, newlen; + char *newstr; + + if(!s || !*s) return; + + len = strlen(s); + newlen = str->len + len; + if(!(newstr = malloc(newlen + 2))) { /* leave space for a possible newline */ + fprintf(stderr, "shader composition: failed to append string of size %d\n", len); + abort(); + } + + if(str->text) { + memcpy(newstr, str->text, str->len); + } + memcpy(newstr + str->len, s, len + 1); + + if(s[len - 1] != '\n') { + newstr[newlen] = '\n'; + newstr[newlen + 1] = 0; + } + + free(str->text); + str->text = newstr; + str->len = newlen; +} + +void clear_shader_header(unsigned int type) +{ + if(type) { + int idx = sdrtypeidx(type); + clear_string(&header[idx]); + } else { + int i; + for(i=0; i"; +} + +static int sdrtypeidx(unsigned int sdrtype) +{ + switch(sdrtype) { + case GL_VERTEX_SHADER: + return 0; + case GL_FRAGMENT_SHADER: + return 1; + case GL_TESS_CONTROL_SHADER: + return 2; + case GL_TESS_EVALUATION_SHADER: + return 3; + case GL_GEOMETRY_SHADER: + return 4; + default: + break; + } + return 0; +} diff --git a/src/sdr.h b/src/sdr.h new file mode 100644 index 0000000..7bf2389 --- /dev/null +++ b/src/sdr.h @@ -0,0 +1,68 @@ +#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 get_uniform_loc(unsigned int prog, const char *name); + +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, const float *mat); +int set_uniform_matrix4_transposed(unsigned int prog, const char *name, const 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); + +/* ---- shader composition ---- */ + +/* clear shader header/footer text. + * pass the shader type to clear, or 0 to clear all types */ +void clear_shader_header(unsigned int type); +void clear_shader_footer(unsigned int type); +/* append text to the header/footer of a specific shader type + * or use type 0 to add it to all shade types */ +void add_shader_header(unsigned int type, const char *s); +void add_shader_footer(unsigned int type, const char *s); +/* get the current header/footer text for a specific shader type */ +const char *get_shader_header(unsigned int type); +const char *get_shader_footer(unsigned int type); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* SDR_H_ */ -- 1.7.10.4