# HG changeset patch # User John Tsiombikas # Date 1315285634 -10800 # Node ID 1bb950d0976b0b61fcabc3c971c9dd8686021196 initial commit diff -r 000000000000 -r 1bb950d0976b src/EAGLView.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/EAGLView.h Tue Sep 06 08:07:14 2011 +0300 @@ -0,0 +1,40 @@ +// +// EAGLView.h +// istereo +// +// Created by nuclear on 9/6/11. +// Copyright __MyCompanyName__ 2011. All rights reserved. +// + +#import +#import + +#import "ESRenderer.h" + +// This class wraps the CAEAGLLayer from CoreAnimation into a convenient UIView subclass. +// The view content is basically an EAGL surface you render your OpenGL scene into. +// Note that setting the view non-opaque will only work if the EAGL surface has an alpha channel. +@interface EAGLView : UIView +{ +@private + id renderer; + + BOOL animating; + BOOL displayLinkSupported; + NSInteger animationFrameInterval; + // Use of the CADisplayLink class is the preferred method for controlling your animation timing. + // CADisplayLink will link to the main display and fire every vsync when added to a given run-loop. + // The NSTimer class is used only as fallback when running on a pre 3.1 device where CADisplayLink + // isn't available. + id displayLink; + NSTimer *animationTimer; +} + +@property (readonly, nonatomic, getter=isAnimating) BOOL animating; +@property (nonatomic) NSInteger animationFrameInterval; + +- (void)startAnimation; +- (void)stopAnimation; +- (void)drawView:(id)sender; + +@end diff -r 000000000000 -r 1bb950d0976b src/EAGLView.m --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/EAGLView.m Tue Sep 06 08:07:14 2011 +0300 @@ -0,0 +1,150 @@ +// +// EAGLView.m +// istereo +// +// Created by nuclear on 9/6/11. +// Copyright __MyCompanyName__ 2011. All rights reserved. +// + +#import "EAGLView.h" + +#import "ES1Renderer.h" +#import "ES2Renderer.h" + +@implementation EAGLView + +@synthesize animating; +@dynamic animationFrameInterval; + +// You must implement this method ++ (Class)layerClass +{ + return [CAEAGLLayer class]; +} + +//The EAGL view is stored in the nib file. When it's unarchived it's sent -initWithCoder: +- (id)initWithCoder:(NSCoder*)coder +{ + if ((self = [super initWithCoder:coder])) + { + // Get the layer + CAEAGLLayer *eaglLayer = (CAEAGLLayer *)self.layer; + + eaglLayer.opaque = TRUE; + eaglLayer.drawableProperties = [NSDictionary dictionaryWithObjectsAndKeys: + [NSNumber numberWithBool:FALSE], kEAGLDrawablePropertyRetainedBacking, kEAGLColorFormatRGBA8, kEAGLDrawablePropertyColorFormat, nil]; + + renderer = [[ES2Renderer alloc] init]; + + if (!renderer) + { + renderer = [[ES1Renderer alloc] init]; + + if (!renderer) + { + [self release]; + return nil; + } + } + + animating = FALSE; + displayLinkSupported = FALSE; + animationFrameInterval = 1; + displayLink = nil; + animationTimer = nil; + + // A system version of 3.1 or greater is required to use CADisplayLink. The NSTimer + // class is used as fallback when it isn't available. + NSString *reqSysVer = @"3.1"; + NSString *currSysVer = [[UIDevice currentDevice] systemVersion]; + if ([currSysVer compare:reqSysVer options:NSNumericSearch] != NSOrderedAscending) + displayLinkSupported = TRUE; + } + + return self; +} + +- (void)drawView:(id)sender +{ + [renderer render]; +} + +- (void)layoutSubviews +{ + [renderer resizeFromLayer:(CAEAGLLayer*)self.layer]; + [self drawView:nil]; +} + +- (NSInteger)animationFrameInterval +{ + return animationFrameInterval; +} + +- (void)setAnimationFrameInterval:(NSInteger)frameInterval +{ + // Frame interval defines how many display frames must pass between each time the + // display link fires. The display link will only fire 30 times a second when the + // frame internal is two on a display that refreshes 60 times a second. The default + // frame interval setting of one will fire 60 times a second when the display refreshes + // at 60 times a second. A frame interval setting of less than one results in undefined + // behavior. + if (frameInterval >= 1) + { + animationFrameInterval = frameInterval; + + if (animating) + { + [self stopAnimation]; + [self startAnimation]; + } + } +} + +- (void)startAnimation +{ + if (!animating) + { + if (displayLinkSupported) + { + // CADisplayLink is API new to iPhone SDK 3.1. Compiling against earlier versions will result in a warning, but can be dismissed + // if the system version runtime check for CADisplayLink exists in -initWithCoder:. The runtime check ensures this code will + // not be called in system versions earlier than 3.1. + + displayLink = [NSClassFromString(@"CADisplayLink") displayLinkWithTarget:self selector:@selector(drawView:)]; + [displayLink setFrameInterval:animationFrameInterval]; + [displayLink addToRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode]; + } + else + animationTimer = [NSTimer scheduledTimerWithTimeInterval:(NSTimeInterval)((1.0 / 60.0) * animationFrameInterval) target:self selector:@selector(drawView:) userInfo:nil repeats:TRUE]; + + animating = TRUE; + } +} + +- (void)stopAnimation +{ + if (animating) + { + if (displayLinkSupported) + { + [displayLink invalidate]; + displayLink = nil; + } + else + { + [animationTimer invalidate]; + animationTimer = nil; + } + + animating = FALSE; + } +} + +- (void)dealloc +{ + [renderer release]; + + [super dealloc]; +} + +@end diff -r 000000000000 -r 1bb950d0976b src/ES1Renderer.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/ES1Renderer.h Tue Sep 06 08:07:14 2011 +0300 @@ -0,0 +1,30 @@ +// +// ES1Renderer.h +// istereo +// +// Created by nuclear on 9/6/11. +// Copyright __MyCompanyName__ 2011. All rights reserved. +// + +#import "ESRenderer.h" + +#import +#import + +@interface ES1Renderer : NSObject +{ +@private + EAGLContext *context; + + // The pixel dimensions of the CAEAGLLayer + GLint backingWidth; + GLint backingHeight; + + // The OpenGL ES names for the framebuffer and renderbuffer used to render to this view + GLuint defaultFramebuffer, colorRenderbuffer; +} + +- (void)render; +- (BOOL)resizeFromLayer:(CAEAGLLayer *)layer; + +@end diff -r 000000000000 -r 1bb950d0976b src/ES1Renderer.m --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/ES1Renderer.m Tue Sep 06 08:07:14 2011 +0300 @@ -0,0 +1,131 @@ +// +// ES1Renderer.m +// istereo +// +// Created by nuclear on 9/6/11. +// Copyright __MyCompanyName__ 2011. All rights reserved. +// + +#import "ES1Renderer.h" + +@implementation ES1Renderer + +// Create an OpenGL ES 1.1 context +- (id)init +{ + if ((self = [super init])) + { + context = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES1]; + + if (!context || ![EAGLContext setCurrentContext:context]) + { + [self release]; + return nil; + } + + // Create default framebuffer object. The backing will be allocated for the current layer in -resizeFromLayer + glGenFramebuffersOES(1, &defaultFramebuffer); + glGenRenderbuffersOES(1, &colorRenderbuffer); + glBindFramebufferOES(GL_FRAMEBUFFER_OES, defaultFramebuffer); + glBindRenderbufferOES(GL_RENDERBUFFER_OES, colorRenderbuffer); + glFramebufferRenderbufferOES(GL_FRAMEBUFFER_OES, GL_COLOR_ATTACHMENT0_OES, GL_RENDERBUFFER_OES, colorRenderbuffer); + } + + return self; +} + +- (void)render +{ + // Replace the implementation of this method to do your own custom drawing + + static const GLfloat squareVertices[] = { + -0.5f, -0.33f, + 0.5f, -0.33f, + -0.5f, 0.33f, + 0.5f, 0.33f, + }; + + static const GLubyte squareColors[] = { + 255, 255, 0, 255, + 0, 255, 255, 255, + 0, 0, 0, 0, + 255, 0, 255, 255, + }; + + static float transY = 0.0f; + + // This application only creates a single context which is already set current at this point. + // This call is redundant, but needed if dealing with multiple contexts. + [EAGLContext setCurrentContext:context]; + + // This application only creates a single default framebuffer which is already bound at this point. + // This call is redundant, but needed if dealing with multiple framebuffers. + glBindFramebufferOES(GL_FRAMEBUFFER_OES, defaultFramebuffer); + glViewport(0, 0, backingWidth, backingHeight); + + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + glMatrixMode(GL_MODELVIEW); + glLoadIdentity(); + glTranslatef(0.0f, (GLfloat)(sinf(transY)/2.0f), 0.0f); + transY += 0.075f; + + glClearColor(0.5f, 0.5f, 0.5f, 1.0f); + glClear(GL_COLOR_BUFFER_BIT); + + glVertexPointer(2, GL_FLOAT, 0, squareVertices); + glEnableClientState(GL_VERTEX_ARRAY); + glColorPointer(4, GL_UNSIGNED_BYTE, 0, squareColors); + glEnableClientState(GL_COLOR_ARRAY); + + glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); + + // This application only creates a single color renderbuffer which is already bound at this point. + // This call is redundant, but needed if dealing with multiple renderbuffers. + glBindRenderbufferOES(GL_RENDERBUFFER_OES, colorRenderbuffer); + [context presentRenderbuffer:GL_RENDERBUFFER_OES]; +} + +- (BOOL)resizeFromLayer:(CAEAGLLayer *)layer +{ + // Allocate color buffer backing based on the current layer size + glBindRenderbufferOES(GL_RENDERBUFFER_OES, colorRenderbuffer); + [context renderbufferStorage:GL_RENDERBUFFER_OES fromDrawable:layer]; + glGetRenderbufferParameterivOES(GL_RENDERBUFFER_OES, GL_RENDERBUFFER_WIDTH_OES, &backingWidth); + glGetRenderbufferParameterivOES(GL_RENDERBUFFER_OES, GL_RENDERBUFFER_HEIGHT_OES, &backingHeight); + + if (glCheckFramebufferStatusOES(GL_FRAMEBUFFER_OES) != GL_FRAMEBUFFER_COMPLETE_OES) + { + NSLog(@"Failed to make complete framebuffer object %x", glCheckFramebufferStatusOES(GL_FRAMEBUFFER_OES)); + return NO; + } + + return YES; +} + +- (void)dealloc +{ + // Tear down GL + if (defaultFramebuffer) + { + glDeleteFramebuffersOES(1, &defaultFramebuffer); + defaultFramebuffer = 0; + } + + if (colorRenderbuffer) + { + glDeleteRenderbuffersOES(1, &colorRenderbuffer); + colorRenderbuffer = 0; + } + + // Tear down context + if ([EAGLContext currentContext] == context) + [EAGLContext setCurrentContext:nil]; + + [context release]; + context = nil; + + [super dealloc]; +} + +@end diff -r 000000000000 -r 1bb950d0976b src/ES2Renderer.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/ES2Renderer.h Tue Sep 06 08:07:14 2011 +0300 @@ -0,0 +1,33 @@ +// +// ES2Renderer.h +// istereo +// +// Created by nuclear on 9/6/11. +// Copyright __MyCompanyName__ 2011. All rights reserved. +// + +#import "ESRenderer.h" + +#import +#import + +@interface ES2Renderer : NSObject +{ +@private + EAGLContext *context; + + // The pixel dimensions of the CAEAGLLayer + GLint backingWidth; + GLint backingHeight; + + // The OpenGL ES names for the framebuffer and renderbuffer used to render to this view + GLuint defaultFramebuffer, colorRenderbuffer; + + GLuint program; +} + +- (void)render; +- (BOOL)resizeFromLayer:(CAEAGLLayer *)layer; + +@end + diff -r 000000000000 -r 1bb950d0976b src/ES2Renderer.m --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/ES2Renderer.m Tue Sep 06 08:07:14 2011 +0300 @@ -0,0 +1,93 @@ +#import "ES2Renderer.h" +#include "istereo.h" + +@implementation ES2Renderer + +// Create an OpenGL ES 2.0 context +- (id)init +{ + if ((self = [super init])) + { + context = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES2]; + + if (!context || ![EAGLContext setCurrentContext:context]) + { + [self release]; + return nil; + } + + // Create default framebuffer object. The backing will be allocated for the current layer in -resizeFromLayer + glGenFramebuffers(1, &defaultFramebuffer); + glGenRenderbuffers(1, &colorRenderbuffer); + glBindFramebuffer(GL_FRAMEBUFFER, defaultFramebuffer); + glBindRenderbuffer(GL_RENDERBUFFER, colorRenderbuffer); + glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, colorRenderbuffer); + + init(); + } + + return self; +} + +- (void)render +{ + redraw(); + // This application only creates a single default framebuffer which is already bound at this point. + // This call is redundant, but needed if dealing with multiple framebuffers. + //glBindFramebuffer(GL_FRAMEBUFFER, defaultFramebuffer); + //glViewport(0, 0, backingWidth, backingHeight); + + // This call is redundant, but needed if dealing with multiple renderbuffers. + //glBindRenderbuffer(GL_RENDERBUFFER, colorRenderbuffer); + [context presentRenderbuffer:GL_RENDERBUFFER]; +} + +- (BOOL)resizeFromLayer:(CAEAGLLayer *)layer +{ + // Allocate color buffer backing based on the current layer size + glBindRenderbuffer(GL_RENDERBUFFER, colorRenderbuffer); + [context renderbufferStorage:GL_RENDERBUFFER fromDrawable:layer]; + glGetRenderbufferParameteriv(GL_RENDERBUFFER, GL_RENDERBUFFER_WIDTH, &backingWidth); + glGetRenderbufferParameteriv(GL_RENDERBUFFER, GL_RENDERBUFFER_HEIGHT, &backingHeight); + + if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) + { + NSLog(@"Failed to make complete framebuffer object %x", glCheckFramebufferStatus(GL_FRAMEBUFFER)); + return NO; + } + + return YES; +} + +- (void)dealloc +{ + // Tear down GL + if (defaultFramebuffer) + { + glDeleteFramebuffers(1, &defaultFramebuffer); + defaultFramebuffer = 0; + } + + if (colorRenderbuffer) + { + glDeleteRenderbuffers(1, &colorRenderbuffer); + colorRenderbuffer = 0; + } + + if (program) + { + glDeleteProgram(program); + program = 0; + } + + // Tear down context + if ([EAGLContext currentContext] == context) + [EAGLContext setCurrentContext:nil]; + + [context release]; + context = nil; + + [super dealloc]; +} + +@end diff -r 000000000000 -r 1bb950d0976b src/ESRenderer.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/ESRenderer.h Tue Sep 06 08:07:14 2011 +0300 @@ -0,0 +1,19 @@ +// +// ESRenderer.h +// istereo +// +// Created by nuclear on 9/6/11. +// Copyright __MyCompanyName__ 2011. All rights reserved. +// + +#import + +#import +#import + +@protocol ESRenderer + +- (void)render; +- (BOOL)resizeFromLayer:(CAEAGLLayer *)layer; + +@end diff -r 000000000000 -r 1bb950d0976b src/istereo.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/istereo.c Tue Sep 06 08:07:14 2011 +0300 @@ -0,0 +1,17 @@ +#include +#include "istereo.h" + +int init(void) +{ + return 0; +} + +void cleanup(void) +{ +} + +void redraw(void) +{ + glClearColor(0, 1, 0, 1); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); +} diff -r 000000000000 -r 1bb950d0976b src/istereo.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/istereo.h Tue Sep 06 08:07:14 2011 +0300 @@ -0,0 +1,8 @@ +#ifndef ISTEREO_H_ +#define ISTEREO_H_ + +int init(void); +void cleanup(void); +void redraw(void); + +#endif /* ISTEREO_H_ */ diff -r 000000000000 -r 1bb950d0976b src/istereoAppDelegate.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/istereoAppDelegate.h Tue Sep 06 08:07:14 2011 +0300 @@ -0,0 +1,22 @@ +// +// istereoAppDelegate.h +// istereo +// +// Created by nuclear on 9/6/11. +// Copyright __MyCompanyName__ 2011. All rights reserved. +// + +#import + +@class EAGLView; + +@interface istereoAppDelegate : NSObject { + UIWindow *window; + EAGLView *glView; +} + +@property (nonatomic, retain) IBOutlet UIWindow *window; +@property (nonatomic, retain) IBOutlet EAGLView *glView; + +@end + diff -r 000000000000 -r 1bb950d0976b src/istereoAppDelegate.m --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/istereoAppDelegate.m Tue Sep 06 08:07:14 2011 +0300 @@ -0,0 +1,46 @@ +// +// istereoAppDelegate.m +// istereo +// +// Created by nuclear on 9/6/11. +// Copyright __MyCompanyName__ 2011. All rights reserved. +// + +#import "istereoAppDelegate.h" +#import "EAGLView.h" + +@implementation istereoAppDelegate + +@synthesize window; +@synthesize glView; + +- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions +{ + [glView startAnimation]; + return YES; +} + +- (void)applicationWillResignActive:(UIApplication *)application +{ + [glView stopAnimation]; +} + +- (void)applicationDidBecomeActive:(UIApplication *)application +{ + [glView startAnimation]; +} + +- (void)applicationWillTerminate:(UIApplication *)application +{ + [glView stopAnimation]; +} + +- (void)dealloc +{ + [window release]; + [glView release]; + + [super dealloc]; +} + +@end diff -r 000000000000 -r 1bb950d0976b src/main.m --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/main.m Tue Sep 06 08:07:14 2011 +0300 @@ -0,0 +1,17 @@ +// +// main.m +// istereo +// +// Created by nuclear on 9/6/11. +// Copyright __MyCompanyName__ 2011. All rights reserved. +// + +#import + +int main(int argc, char *argv[]) { + + NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init]; + int retVal = UIApplicationMain(argc, argv, nil, nil); + [pool release]; + return retVal; +} diff -r 000000000000 -r 1bb950d0976b src/sdr.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/sdr.c Tue Sep 06 08:07:14 2011 +0300 @@ -0,0 +1,323 @@ +#include +#include +#include +#include +#include +#include + +#if defined(unix) || defined(__unix__) +#include +#include +#endif /* unix */ + +#include "sdr.h" + + +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_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_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... ", (sdr_type == GL_VERTEX_SHADER ? "vertex" : "pixel"), 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_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 vs, unsigned int ps) +{ + unsigned int prog; + + if(!(prog = create_program())) { + return 0; + } + + attach_shader(prog, vs); + assert(glGetError() == GL_NO_ERROR); + attach_shader(prog, ps); + assert(glGetError() == GL_NO_ERROR); + + 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, ps; + + if(!(vs = get_vertex_shader(vfile)) || !(ps = get_pixel_shader(pfile))) { + return 0; + } + return create_program_link(vs, ps); +} + +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(curr_prog != prog && bind_program(prog) == -1) { \ + return -1; \ + } \ + if((loc = glGetUniformLocation(prog, name)) != -1) + +#define END_UNIFORM_CODE \ + if(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_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, 16, GL_FALSE, mat); + } + END_UNIFORM_CODE; +} + +int set_uniform_matrix4_transposed(unsigned int prog, const char *name, float *mat) +{ + BEGIN_UNIFORM_CODE { + glUniformMatrix4fv(loc, 16, 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(curr_prog != prog && bind_program(prog) == -1) { + return -1; + } + + loc = glGetAttribLocation(prog, (char*)name); + + if(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); +} diff -r 000000000000 -r 1bb950d0976b src/sdr.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/sdr.h Tue Sep 06 08:07:14 2011 +0300 @@ -0,0 +1,49 @@ +#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_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_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_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 vs, unsigned int ps); +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_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_ */