Skip to content

Instantly share code, notes, and snippets.

@graphitemaster
Created May 14, 2012 20:12
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save graphitemaster/2696371 to your computer and use it in GitHub Desktop.
Save graphitemaster/2696371 to your computer and use it in GitHub Desktop.
Deferred Renderer - 350LOC
/*
* A simple deferred renderer using OpenGL, C90 and SDL, plugin and use
* with no issue at all. All code is public domain -- Dale Weiler 2012
* a.k.a graphitemaster
*/
#include <SDL.h>
#include <SDL/SDL_opengl.h>
typedef struct {
GLuint fbo;
GLuint diffuse_target, diffuse_texture;
GLuint position_target, position_texture;
GLuint normals_target, normals_texture;
GLuint depthbuffer;
GLuint width,height;
} r_fbo;
typedef struct {
GLhandleARB shader_vert;
GLhandleARB shader_frag;
GLhandleARB shader_prog;
const char *vsfilename;
const char *fsfilename;
} r_shader;
typedef struct {
r_shader *shader;
r_fbo *fbo;
GLuint width, height;
GLuint id_diffuse;
GLuint id_position;
GLuint id_normals;
} r_def;
typedef struct {
r_shader *shader;
GLuint worldmatrix;
float rotation_x,rotation_y,rotation_z;
float position_x,position_y,position_z;
GLuint texture, ogltex;
} r_mdl;
r_shader *r_shader_make(const char *vsfilename, const char *fsfilename) {
r_shader *shader = malloc(sizeof(r_shader));
shader->vsfilename = vsfilename;
shader->fsfilename = fsfilename;
shader->shader_vert = glCreateShaderObjectARB(GL_VERTEX_SHADER_ARB);
shader->shader_frag = glCreateShaderObjectARB(GL_FRAGMENT_SHADER_ARB);
char *vd,*fd;
FILE *sf = NULL;
long count = 0;
/* vertex load */
sf = fopen(vsfilename, "r");
if (!sf) {
printf("r: failed to load vertex shader %s\n", vsfilename);
abort ();
}
fseek(sf, 0, SEEK_END);
count = ftell(sf);
rewind(sf);
vd = malloc(count + 1);
memset(vd, 0, count+1);
fread (vd, 1, count, sf);
fclose(sf); sf = NULL;
/* fragment load */
sf = fopen(fsfilename, "r");
if (!sf) {
printf("r: failed to load fragment shader %s\n", fsfilename);
abort ();
}
fseek(sf, 0, SEEK_END);
count = ftell(sf);
rewind(sf);
fd = malloc(count + 1);
memset(fd, 0, count+1);
fread (fd, 1, count, sf);
fclose(sf); sf = NULL;
int compiled = 0;
glShaderSourceARB (shader->shader_vert, 1, &vd, NULL);
glCompileShaderARB (shader->shader_vert);
glGetObjectParameterivARB(shader->shader_vert, GL_OBJECT_COMPILE_STATUS_ARB, &compiled);
if (compiled == 0) {
printf("r: failed to compile vertex shader %s\n", vsfilename);
abort ();
}
glShaderSourceARB (shader->shader_frag, 1, &fd, NULL);
glCompileShaderARB (shader->shader_frag);
glGetObjectParameterivARB(shader->shader_frag, GL_OBJECT_COMPILE_STATUS_ARB, &compiled);
if (compiled == 0) {
printf("r: failed to compile fragment shader %s\n", fsfilename);
abort ();
}
shader->shader_prog = glCreateProgramObjectARB();
glAttachObjectARB(shader->shader_prog, shader->shader_vert);
glAttachObjectARB(shader->shader_prog, shader->shader_frag);
glLinkProgramARB (shader->shader_prog);
free(vd);
free(fd);
return shader;
}
r_mdl *r_mdl_make(const char *vsfilename, const char *fsfilename) {
r_mdl *mdl = malloc(sizeof(r_mdl));
mdl->ogltex = 0;
mdl->shader = r_shader_make(vsfilename, fsfilename);
mdl->rotation_x = mdl->rotation_y = mdl->rotation_z = 0;
mdl->position_x = mdl->position_y = mdl->position_z = 0;
mdl->worldmatrix = glGetUniformLocationARB(mdl->shader->shader_prog, "t_pos");
mdl->texture = glGetUniformLocationARB(mdl->shader->shader_prog, "t_dif");
return mdl;
}
r_def *r_def_make(int w, int h, r_fbo *fbo) {
r_def *def = malloc(sizeof(r_def));
def->shader = r_shader_make("data/dr.vs", "data/dr.fs");
def->fbo = fbo;
def->width = w;
def->height = h;
def->id_diffuse = glGetUniformLocationARB(def->shader->shader_prog, "t_dif");
def->id_position = glGetUniformLocationARB(def->shader->shader_prog, "t_pos");
def->id_normals = glGetUniformLocationARB(def->shader->shader_prog, "t_nrm");
}
void r_def_render(const r_def *def) {
glMatrixMode (GL_PROJECTION);
glPushMatrix ();
glLoadIdentity ();
glOrtho (0, def->width, 0, def->height, 0.1f, 2);
glMatrixMode (GL_MODELVIEW);
glPushMatrix ();
glUseProgramObjectARB (def->shader->shader_prog);
glActiveTextureARB (GL_TEXTURE0_ARB);
glEnable (GL_TEXTURE_2D);
glBindTexture (GL_TEXTURE_2D, def->fbo->diffuse_texture);
glUniform1iARB (def->id_diffuse, 0);
glActiveTextureARB (GL_TEXTURE1_ARB);
glEnable (GL_TEXTURE_2D);
glBindTexture (GL_TEXTURE_2D, def->fbo->position_texture);
glUniform1iARB (def->id_position,1);
glActiveTextureARB (GL_TEXTURE2_ARB);
glEnable (GL_TEXTURE_2D);
glBindTexture (GL_TEXTURE_2D, def->fbo->normals_texture);
glUniform1iARB (def->id_normals, 2);
glLoadIdentity ();
glColor3f (1,1,1);
glTranslatef (0,0,-1.0);
glBegin (GL_QUADS);
glTexCoord2f (0, 0); glVertex3f(0.0f, 0.0f, 0.0f);
glTexCoord2f (1, 0); glVertex3f((float)def->width, 0.0f, 0.0f);
glTexCoord2f (1, 1); glVertex3f((float)def->width, (float)def->height, 0.0f);
glTexCoord2f (0, 1); glVertex3f(0.0f, (float)def->height, 0.0f);
glEnd ();
glActiveTextureARB (GL_TEXTURE0_ARB);
glDisable (GL_TEXTURE_2D);
glBindTexture (GL_TEXTURE_2D, 0);
glActiveTextureARB (GL_TEXTURE1_ARB);
glDisable (GL_TEXTURE_2D);
glBindTexture (GL_TEXTURE_2D, 0);
glActiveTextureARB (GL_TEXTURE1_ARB);
glDisable (GL_TEXTURE_2D);
glBindTexture (GL_TEXTURE_2D, 0);
glUseProgramObjectARB (0);
glMatrixMode (GL_PROJECTION);
glPopMatrix ();
glMatrixMode (GL_MODELVIEW);
glPopMatrix ();
}
r_fbo *r_fbo_make(int w, int h) {
r_fbo *fbo = malloc(sizeof(r_fbo));
fbo->width = w;
fbo->height = h;
glGenFramebuffersEXT(1, &fbo->fbo);
glGenFramebuffersEXT(1, &fbo->diffuse_target);
glGenFramebuffersEXT(1, &fbo->position_target);
glGenFramebuffersEXT(1, &fbo->normals_target);
glGenFramebuffersEXT(1, &fbo->depthbuffer);
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fbo->fbo);
glBindRenderbufferEXT (GL_RENDERBUFFER_EXT, fbo->diffuse_target);
glRenderbufferStorageEXT (GL_RENDERBUFFER_EXT, GL_RGBA, w, h);
glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT , GL_COLOR_ATTACHMENT0_EXT, GL_RENDERBUFFER_EXT, fbo->diffuse_target);
glBindRenderbufferEXT (GL_RENDERBUFFER_EXT, fbo->position_target);
glRenderbufferStorageEXT (GL_RENDERBUFFER_EXT, GL_RGBA32F_ARB, w, h);
glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT , GL_COLOR_ATTACHMENT1_EXT, GL_RENDERBUFFER_EXT, fbo->position_target);
glBindRenderbufferEXT (GL_RENDERBUFFER_EXT, fbo->normals_target);
glRenderbufferStorageEXT (GL_RENDERBUFFER_EXT, GL_RGBA16F_ARB, w, h);
glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT , GL_COLOR_ATTACHMENT2_EXT, GL_RENDERBUFFER_EXT, fbo->normals_target);
glBindRenderbufferEXT (GL_RENDERBUFFER_EXT, fbo->depthbuffer);
glRenderbufferStorageEXT (GL_RENDERBUFFER_EXT, GL_DEPTH_COMPONENT24, w, h);
glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT , GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, fbo->depthbuffer);
glGenTextures(1, &fbo->diffuse_texture);
glGenTextures(1, &fbo->position_texture);
glGenTextures(1, &fbo->normals_texture);
glBindTexture (GL_TEXTURE_2D, fbo->diffuse_texture);
glTexImage2D (GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, fbo->diffuse_texture, 0);
glBindTexture (GL_TEXTURE_2D, fbo->position_texture);
glTexImage2D (GL_TEXTURE_2D, 0, GL_RGBA32F_ARB, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT1_EXT, GL_TEXTURE_2D, fbo->position_texture, 0);
glBindTexture (GL_TEXTURE_2D, fbo->normals_texture);
glTexImage2D (GL_TEXTURE_2D, 0, GL_RGBA16F_ARB, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT2_EXT, GL_TEXTURE_2D, fbo->normals_texture, 0);
GLenum check = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);
if (check != GL_FRAMEBUFFER_COMPLETE_EXT) {
printf("r: failed to complete FBO target creation\n");
abort();
}
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
return fbo;
}
void r_fbo_start(const r_fbo *fbo) {
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fbo->fbo);
glPushAttrib (GL_VIEWPORT_BIT);
glViewport (0, 0, fbo->width, fbo->height);
glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glClearColor (0.0f, 0.0f, 0.0f, 1.0f);
glActiveTextureARB (GL_TEXTURE0_ARB);
glEnable (GL_TEXTURE_2D);
GLenum buffers[] = {
GL_COLOR_ATTACHMENT0_EXT,GL_COLOR_ATTACHMENT1_EXT,GL_COLOR_ATTACHMENT2_EXT
};
glDrawBuffers(3, buffers);
}
void r_fbo_stop (const r_fbo *fbo) {
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
glPopAttrib ();
}
void r_fbo_show (const r_fbo *fbo, GLuint i, float sx, float sy, float x, float y) {
GLuint tex = fbo->diffuse_texture;
if (i == 1) tex = fbo->position_texture;
else if (i == 2) tex = fbo->normals_texture;
glMatrixMode (GL_PROJECTION);
glPushMatrix ();
glLoadIdentity ();
glOrtho (0, fbo->width, 0, fbo->height, 0.1f, 2);
glMatrixMode (GL_MODELVIEW);
glPushMatrix ();
glActiveTextureARB(GL_TEXTURE0_ARB);
glLoadIdentity ();
glTranslatef (x, -y, -1.0f);
glColor3f (1,1,1);
glBegin (GL_QUADS);
glTexCoord2f (0, 1); glVertex3f(0.0f, (float)fbo->height, 0.0f);
glTexCoord2f (0, 0); glVertex3f(0.0f, fbo->height-sy, 0.0f);
glTexCoord2f (1, 0); glVertex3f(sx, fbo->height-sy, 0.0f);
glTexCoord2f (1, 1); glVertex3f(sx, (float)fbo->height, 0.0f);
glEnd ();
glBindTexture (GL_TEXTURE_2D, 0);
glMatrixMode (GL_PROJECTION);
glPopMatrix ();
glMatrixMode (GL_MODELVIEW);
glPopMatrix ();
}
void r_mdl_render(r_mdl *mdl, int type) {
glPushMatrix();
switch (type) {
/*
* Write all rendering in here, for some model
*/
}
glUseProgramObjectARB(0);
glPopMatrix();
}
int main() {
const SDL_VideoInfo *info = NULL;
int width = 0;
int height = 0;
int bpp = 0;
int flags = 0;
if (SDL_Init(SDL_INIT_VIDEO) < 0) {
printf("c: failed to initialize video %s\n", SDL_GetError());
abort ();
}
info = SDL_GetVideoInfo();
if (!info) {
printf("c: failed to query video %s\n", SDL_GetError());
abort ();
}
width = 640;
height = 480;
bpp = info->vfmt->BitsPerPixel;
SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 5 );
SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 5 );
SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 5 );
SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 16);
SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1 );
flags = SDL_OPENGL;
if (SDL_SetVideoMode(width, height, bpp, flags) == 0) {
printf("c: failed to set view mode: %s\n", SDL_GetError());
abort ();
}
r_fbo *multi = r_fbo_make(width, height);
r_def *defer = r_def_make(width, height, multi);
r_mdl *level = r_mdl_make([[VERTEX_SHADER_FILE_STRING_HERE]], [[FRAGMENT_SHADER_FILE_STRING_HERE]]);
/* more models are allowed */
level->position_x = 2;
level->position_y = 2.5f;
level->position_z = 0;
glDisable (GL_LIGHTING);
glEnable (GL_TEXTURE_2D);
glShadeModel(GL_SMOOTH);
glEnable (GL_DEPTH_TEST);
glDepthFunc (GL_LEQUAL);
glHint (GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);
SDL_Event e;
for (;;) {
while (SDL_PollEvent(&e))
switch (e.type)
case SDL_QUIT: abort(); break;
glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glClearColor (0.2f, 0.3f, 0.8f, 1.0f);
glLoadIdentity();
glRotatef (20, 1, 0, 0);
glTranslatef (0.0f, -4.6f, -10.0f);
r_fbo_start (multi);
r_mdl_render (level, __COUNTER__); /* handle more models as needed */
r_fbo_stop (multi);
/*
* There is a choice now:
* #1 use the deferred renderer
* #2 use the fixed renderer (to FBO)
*/
r_def_render(defer);
/*
* Replace r_def_render(defer) with r_fbo_show(....)
* to use the fixed pipeline.
*/
SDL_GL_SwapBuffers();
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment