nuclear@0: #include nuclear@0: #include nuclear@0: #include nuclear@0: #include nuclear@0: #include nuclear@0: nuclear@0: #if defined(unix) || defined(__unix__) nuclear@0: #include nuclear@0: #include nuclear@0: #include nuclear@0: #endif /* unix */ nuclear@0: nuclear@0: #if defined(WIN32) || defined(__WIN32__) nuclear@0: #include nuclear@0: nuclear@0: #define glXGetProcAddress wglGetProcAddress nuclear@0: #endif /* windows */ nuclear@0: nuclear@0: #define GL_GLEXT_LEGACY nuclear@0: #include nuclear@0: nuclear@0: #include "sdr.h" nuclear@0: nuclear@0: #ifndef GL_VERSION_2_0 nuclear@0: nuclear@0: #define GL_FRAGMENT_SHADER 0x8B30 nuclear@0: #define GL_VERTEX_SHADER 0x8B31 nuclear@0: #define GL_COMPILE_STATUS 0x8B81 nuclear@0: #define GL_LINK_STATUS 0x8B82 nuclear@0: #define GL_INFO_LOG_LENGTH 0x8B84 nuclear@0: #define GL_CURRENT_PROGRAM 0x8B8D nuclear@0: nuclear@0: typedef char GLchar; nuclear@0: nuclear@0: GLuint (*glCreateProgram)(void); nuclear@0: GLuint (*glCreateShader)(GLenum); nuclear@0: void (*glDeleteProgram)(GLuint); nuclear@0: void (*glDeleteShader)(GLuint); nuclear@0: void (*glCompileShader)(GLuint); nuclear@0: void (*glAttachShader)(GLuint, GLuint); nuclear@0: void (*glGetShaderiv)(GLuint, GLenum, GLint *); nuclear@0: void (*glGetShaderInfoLog)(GLuint, GLsizei, GLsizei *, GLchar *); nuclear@0: void (*glGetProgramiv)(GLuint, GLenum, GLint *); nuclear@0: void (*glGetProgramInfoLog)(GLuint, GLsizei, GLsizei *, GLchar *); nuclear@0: void (*glLinkProgram)(GLuint); nuclear@0: void (*glShaderSource)(GLuint, GLsizei, const GLchar* *, const GLint *); nuclear@0: void (*glUseProgram)(GLuint); nuclear@0: GLint (*glGetUniformLocation)(GLuint, const GLchar *); nuclear@0: void (*glUniform1f)(GLint, GLfloat); nuclear@0: void (*glUniform2f)(GLint, GLfloat, GLfloat); nuclear@0: void (*glUniform3f)(GLint, GLfloat, GLfloat, GLfloat); nuclear@0: void (*glUniform4f)(GLint, GLfloat, GLfloat, GLfloat, GLfloat); nuclear@0: void (*glUniform1i)(GLint, GLint); nuclear@0: void (*glUniformMatrix4fv)(GLint, GLsizei, GLboolean, const GLfloat *); nuclear@0: GLint (*glGetAttribLocation)(GLuint, const GLchar *); nuclear@0: void (*glVertexAttrib3f)(GLint, GLfloat, GLfloat, GLfloat); nuclear@0: nuclear@0: void init_sdr(void) nuclear@0: { nuclear@0: glCreateProgram = glXGetProcAddress("glCreateProgramObjectARB"); nuclear@0: glCreateShader = glXGetProcAddress("glCreateShaderObjectARB"); nuclear@0: glDeleteProgram = glXGetProcAddress("glDeleteObjectARB"); nuclear@0: glDeleteShader = glXGetProcAddress("glDeleteObjectARB"); nuclear@0: glCompileShader = glXGetProcAddress("glCompileShaderARB"); nuclear@0: glAttachShader = glXGetProcAddress("glAttachObjectARB"); nuclear@0: glGetShaderiv = glXGetProcAddress("glGetObjectParameterivARB"); nuclear@0: glGetShaderInfoLog = glXGetProcAddress("glGetInfoLogARB"); nuclear@0: glGetProgramiv = glXGetProcAddress("glGetObjectParameterivARB"); nuclear@0: glGetProgramInfoLog = glXGetProcAddress("glGetInfoLogARB"); nuclear@0: glLinkProgram = glXGetProcAddress("glLinkProgramARB"); nuclear@0: glShaderSource = glXGetProcAddress("glShaderSourceARB"); nuclear@0: glUseProgram = glXGetProcAddress("glUseProgramObjectARB"); nuclear@0: glGetUniformLocation = glXGetProcAddress("glGetUniformLocationARB"); nuclear@0: glUniform1f = glXGetProcAddress("glUniform1fARB"); nuclear@0: glUniform2f = glXGetProcAddress("glUniform2fARB"); nuclear@0: glUniform3f = glXGetProcAddress("glUniform3fARB"); nuclear@0: glUniform4f = glXGetProcAddress("glUniform4fARB"); nuclear@0: glUniform1i = glXGetProcAddress("glUniform1iARB"); nuclear@0: glUniformMatrix4fv = glXGetProcAddress("glUniformMatrix4fvARB"); nuclear@0: glGetAttribLocation = glXGetProcAddress("glGetAttribLocationARB"); nuclear@0: glVertexAttrib3f = glXGetProcAddress("glVertexAttrib3fARB"); nuclear@0: } nuclear@0: #else nuclear@0: void init_sdr(void) {} nuclear@0: #endif nuclear@0: nuclear@0: unsigned int create_vertex_shader(const char *src) nuclear@0: { nuclear@0: return create_shader(src, GL_VERTEX_SHADER); nuclear@0: } nuclear@0: nuclear@0: unsigned int create_pixel_shader(const char *src) nuclear@0: { nuclear@0: return create_shader(src, GL_FRAGMENT_SHADER); nuclear@0: } nuclear@0: nuclear@0: unsigned int create_shader(const char *src, unsigned int sdr_type) nuclear@0: { nuclear@0: unsigned int sdr; nuclear@0: int success, info_len; nuclear@0: char *info_str = 0; nuclear@0: GLenum err; nuclear@0: nuclear@0: sdr = glCreateShader(sdr_type); nuclear@0: assert(glGetError() == GL_NO_ERROR); nuclear@0: glShaderSource(sdr, 1, &src, 0); nuclear@0: err = glGetError(); nuclear@0: assert(err == GL_NO_ERROR); nuclear@0: glCompileShader(sdr); nuclear@0: assert(glGetError() == GL_NO_ERROR); nuclear@0: nuclear@0: glGetShaderiv(sdr, GL_COMPILE_STATUS, &success); nuclear@0: assert(glGetError() == GL_NO_ERROR); nuclear@0: glGetShaderiv(sdr, GL_INFO_LOG_LENGTH, &info_len); nuclear@0: assert(glGetError() == GL_NO_ERROR); nuclear@0: nuclear@0: if(info_len) { nuclear@0: if((info_str = malloc(info_len + 1))) { nuclear@0: glGetShaderInfoLog(sdr, info_len, 0, info_str); nuclear@0: assert(glGetError() == GL_NO_ERROR); nuclear@0: } nuclear@0: } nuclear@0: nuclear@0: if(success) { nuclear@0: fprintf(stderr, info_str ? "done: %s\n" : "done\n", info_str); nuclear@0: } else { nuclear@0: fprintf(stderr, info_str ? "failed: %s\n" : "failed\n", info_str); nuclear@0: glDeleteShader(sdr); nuclear@0: sdr = 0; nuclear@0: } nuclear@0: nuclear@0: free(info_str); nuclear@0: return sdr; nuclear@0: } nuclear@0: nuclear@0: void free_shader(unsigned int sdr) nuclear@0: { nuclear@0: glDeleteShader(sdr); nuclear@0: } nuclear@0: nuclear@0: unsigned int load_vertex_shader(const char *fname) nuclear@0: { nuclear@0: return load_shader(fname, GL_VERTEX_SHADER); nuclear@0: } nuclear@0: nuclear@0: unsigned int load_pixel_shader(const char *fname) nuclear@0: { nuclear@0: return load_shader(fname, GL_FRAGMENT_SHADER); nuclear@0: } nuclear@0: nuclear@0: unsigned int load_shader(const char *fname, unsigned int sdr_type) nuclear@0: { nuclear@0: #if defined(unix) || defined(__unix__) nuclear@0: struct stat st; nuclear@0: #endif nuclear@0: unsigned int sdr; nuclear@0: size_t filesize; nuclear@0: FILE *fp; nuclear@0: char *src; nuclear@0: nuclear@0: if(!(fp = fopen(fname, "r"))) { nuclear@0: fprintf(stderr, "failed to open shader %s: %s\n", fname, strerror(errno)); nuclear@0: return 0; nuclear@0: } nuclear@0: nuclear@0: #if defined(unix) || defined(__unix__) nuclear@0: fstat(fileno(fp), &st); nuclear@0: filesize = st.st_size; nuclear@0: #else nuclear@0: fseek(fp, 0, SEEK_END); nuclear@0: filesize = ftell(fp); nuclear@0: fseek(fp, 0, SEEK_SET); nuclear@0: #endif /* unix */ nuclear@0: nuclear@0: if(!(src = malloc(filesize + 1))) { nuclear@0: fclose(fp); nuclear@0: return 0; nuclear@0: } nuclear@0: fread(src, 1, filesize, fp); nuclear@0: src[filesize] = 0; nuclear@0: fclose(fp); nuclear@0: nuclear@0: fprintf(stderr, "compiling %s shader: %s... ", (sdr_type == GL_VERTEX_SHADER ? "vertex" : "pixel"), fname); nuclear@0: sdr = create_shader(src, sdr_type); nuclear@0: nuclear@0: free(src); nuclear@0: return sdr; nuclear@0: } nuclear@0: nuclear@0: nuclear@0: unsigned int get_vertex_shader(const char *fname) nuclear@0: { nuclear@0: return get_shader(fname, GL_VERTEX_SHADER); nuclear@0: } nuclear@0: nuclear@0: unsigned int get_pixel_shader(const char *fname) nuclear@0: { nuclear@0: return get_shader(fname, GL_FRAGMENT_SHADER); nuclear@0: } nuclear@0: nuclear@0: unsigned int get_shader(const char *fname, unsigned int sdr_type) nuclear@0: { nuclear@0: unsigned int sdr; nuclear@0: #if 0 nuclear@0: if((res = get_resource(sdrman, fname))) { nuclear@0: /* TODO: validate that the shader matches sdr_type? */ nuclear@0: return (uintptr_t)res; nuclear@0: } nuclear@0: #endif nuclear@0: nuclear@0: if(!(sdr = load_shader(fname, sdr_type))) { nuclear@0: return 0; nuclear@0: } nuclear@0: add_shader(fname, sdr); nuclear@0: return sdr; nuclear@0: } nuclear@0: nuclear@0: int add_shader(const char *fname, unsigned int sdr) nuclear@0: { nuclear@0: return 0;/*add_resource(sdrman, fname, (void*)(uintptr_t)sdr);*/ nuclear@0: } nuclear@0: nuclear@0: int remove_shader(const char *fname) nuclear@0: { nuclear@0: return 0;/*remove_resource(sdrman, fname);*/ nuclear@0: } nuclear@0: nuclear@0: nuclear@0: /* ---- gpu programs ---- */ nuclear@0: nuclear@0: unsigned int create_program(void) nuclear@0: { nuclear@0: unsigned int prog = glCreateProgram(); nuclear@0: assert(glGetError() == GL_NO_ERROR); nuclear@0: return prog; nuclear@0: } nuclear@0: nuclear@0: unsigned int create_program_link(unsigned int vs, unsigned int ps) nuclear@0: { nuclear@0: unsigned int prog; nuclear@0: nuclear@0: if(!(prog = create_program())) { nuclear@0: return 0; nuclear@0: } nuclear@0: nuclear@0: attach_shader(prog, vs); nuclear@0: assert(glGetError() == GL_NO_ERROR); nuclear@0: attach_shader(prog, ps); nuclear@0: assert(glGetError() == GL_NO_ERROR); nuclear@0: nuclear@0: if(link_program(prog) == -1) { nuclear@0: free_program(prog); nuclear@0: return 0; nuclear@0: } nuclear@0: return prog; nuclear@0: } nuclear@0: nuclear@0: unsigned int create_program_load(const char *vfile, const char *pfile) nuclear@0: { nuclear@0: unsigned int vs, ps; nuclear@0: nuclear@0: if(!(vs = get_vertex_shader(vfile)) || !(ps = get_pixel_shader(pfile))) { nuclear@0: return 0; nuclear@0: } nuclear@0: return create_program_link(vs, ps); nuclear@0: } nuclear@0: nuclear@0: void free_program(unsigned int sdr) nuclear@0: { nuclear@0: glDeleteProgram(sdr); nuclear@0: } nuclear@0: nuclear@0: void attach_shader(unsigned int prog, unsigned int sdr) nuclear@0: { nuclear@0: glAttachShader(prog, sdr); nuclear@0: assert(glGetError() == GL_NO_ERROR); nuclear@0: } nuclear@0: nuclear@0: int link_program(unsigned int prog) nuclear@0: { nuclear@0: int linked, info_len, retval = 0; nuclear@0: char *info_str = 0; nuclear@0: nuclear@0: glLinkProgram(prog); nuclear@0: assert(glGetError() == GL_NO_ERROR); nuclear@0: glGetProgramiv(prog, GL_LINK_STATUS, &linked); nuclear@0: assert(glGetError() == GL_NO_ERROR); nuclear@0: glGetProgramiv(prog, GL_INFO_LOG_LENGTH, &info_len); nuclear@0: assert(glGetError() == GL_NO_ERROR); nuclear@0: nuclear@0: if(info_len) { nuclear@0: if((info_str = malloc(info_len + 1))) { nuclear@0: glGetProgramInfoLog(prog, info_len, 0, info_str); nuclear@0: assert(glGetError() == GL_NO_ERROR); nuclear@0: } nuclear@0: } nuclear@0: nuclear@0: if(linked) { nuclear@0: fprintf(stderr, info_str ? "linking done: %s\n" : "linking done\n", info_str); nuclear@0: } else { nuclear@0: fprintf(stderr, info_str ? "linking failed: %s\n" : "linking failed\n", info_str); nuclear@0: retval = -1; nuclear@0: } nuclear@0: nuclear@0: free(info_str); nuclear@0: return retval; nuclear@0: } nuclear@0: nuclear@0: int bind_program(unsigned int prog) nuclear@0: { nuclear@0: GLenum err; nuclear@0: nuclear@0: glUseProgram(prog); nuclear@0: if(prog && (err = glGetError()) != GL_NO_ERROR) { nuclear@0: /* maybe the program is not linked, try to link first */ nuclear@0: if(err == GL_INVALID_OPERATION) { nuclear@0: if(link_program(prog) == -1) { nuclear@0: return -1; nuclear@0: } nuclear@0: glUseProgram(prog); nuclear@0: return glGetError() == GL_NO_ERROR ? 0 : -1; nuclear@0: } nuclear@0: return -1; nuclear@0: } nuclear@0: return 0; nuclear@0: } nuclear@0: nuclear@0: /* ugly but I'm not going to write the same bloody code over and over */ nuclear@0: #define BEGIN_UNIFORM_CODE \ nuclear@0: int loc, curr_prog; \ nuclear@0: glGetIntegerv(GL_CURRENT_PROGRAM, &curr_prog); \ nuclear@0: if(curr_prog != prog && bind_program(prog) == -1) { \ nuclear@0: return -1; \ nuclear@0: } \ nuclear@0: if((loc = glGetUniformLocation(prog, name)) != -1) nuclear@0: nuclear@0: #define END_UNIFORM_CODE \ nuclear@0: if(curr_prog != prog) { \ nuclear@0: bind_program(curr_prog); \ nuclear@0: } \ nuclear@0: return loc == -1 ? -1 : 0 nuclear@0: nuclear@0: int set_uniform_int(unsigned int prog, const char *name, int val) nuclear@0: { nuclear@0: BEGIN_UNIFORM_CODE { nuclear@0: glUniform1i(loc, val); nuclear@0: } nuclear@0: END_UNIFORM_CODE; nuclear@0: } nuclear@0: nuclear@0: int set_uniform_float(unsigned int prog, const char *name, float val) nuclear@0: { nuclear@0: BEGIN_UNIFORM_CODE { nuclear@0: glUniform1f(loc, val); nuclear@0: } nuclear@0: END_UNIFORM_CODE; nuclear@0: } nuclear@0: nuclear@0: int set_uniform_vec2(unsigned int prog, const char *name, vec2_t val) nuclear@0: { nuclear@0: BEGIN_UNIFORM_CODE { nuclear@0: glUniform2f(loc, val.x, val.y); nuclear@0: } nuclear@0: END_UNIFORM_CODE; nuclear@0: } nuclear@0: nuclear@0: int set_uniform_vec3(unsigned int prog, const char *name, vec3_t val) nuclear@0: { nuclear@0: BEGIN_UNIFORM_CODE { nuclear@0: glUniform3f(loc, val.x, val.y, val.z); nuclear@0: } nuclear@0: END_UNIFORM_CODE; nuclear@0: } nuclear@0: nuclear@0: int set_uniform_vec4(unsigned int prog, const char *name, vec4_t val) nuclear@0: { nuclear@0: BEGIN_UNIFORM_CODE { nuclear@0: glUniform4f(loc, val.x, val.y, val.z, val.w); nuclear@0: } nuclear@0: END_UNIFORM_CODE; nuclear@0: } nuclear@0: nuclear@0: int set_uniform_mat4(unsigned int prog, const char *name, mat4_t val) nuclear@0: { nuclear@0: BEGIN_UNIFORM_CODE { nuclear@0: glUniformMatrix4fv(loc, 1, 1, (float*)val); nuclear@0: } nuclear@0: END_UNIFORM_CODE; nuclear@0: } nuclear@0: nuclear@0: nuclear@0: int get_attrib_loc(unsigned int prog, const char *name) nuclear@0: { nuclear@0: int loc, curr_prog; nuclear@0: nuclear@0: glGetIntegerv(GL_CURRENT_PROGRAM, &curr_prog); nuclear@0: if(curr_prog != prog && bind_program(prog) == -1) { nuclear@0: return -1; nuclear@0: } nuclear@0: nuclear@0: loc = glGetAttribLocation(prog, (char*)name); nuclear@0: nuclear@0: if(curr_prog != prog) { nuclear@0: bind_program(curr_prog); nuclear@0: } nuclear@0: return loc; nuclear@0: } nuclear@0: nuclear@0: void set_attrib_vec3(int attr_loc, vec3_t val) nuclear@0: { nuclear@0: glVertexAttrib3f(attr_loc, val.x, val.y, val.z); nuclear@0: } nuclear@0: nuclear@0: void set_attrib_float3(int attr_loc, float x, float y, float z) nuclear@0: { nuclear@0: glVertexAttrib3f(attr_loc, x, y, z); nuclear@0: }