/* * render.c * * Render the scene * * (c) 2008 Thomas White * * thrust3d - a silly game * */ #ifdef HAVE_CONFIG_H #include #endif #include #include #include #include #include #include "model.h" #include "game.h" #include "render.h" #include "texture.h" #include "utils.h" #define PANEL_ALPHA 0.3 /* Utility function to load and compile a shader, checking the info log */ static GLuint render_load_shader(const char *filename, GLenum type) { GLuint shader; char text[4096]; size_t len; FILE *fh; int l; GLint status; fh = fopen(filename, "r"); if ( fh == NULL ) { fprintf(stderr, "Couldn't load shader '%s'\n", filename); return 0; } len = fread(text, 1, 4095, fh); fclose(fh); text[len] = '\0'; const GLchar *source = text; shader = glCreateShader(type); glShaderSource(shader, 1, &source, NULL); glCompileShader(shader); glGetShaderiv(shader, GL_COMPILE_STATUS, &status); if ( status == GL_FALSE ) { glGetShaderInfoLog(shader, 4095, &l, text); if ( l > 0 ) { printf("%s\n", text); fflush(stdout); } else { printf("Shader compilation failed.\n"); } } return shader; } static int render_validate_shader(GLuint shader) { GLint status; int l; char text[4096]; glValidateProgram(shader); glGetProgramiv(shader, GL_VALIDATE_STATUS, &status); if ( status == GL_FALSE ) { glGetProgramInfoLog(shader, 4095, &l, text); if ( l > 0 ) { printf("%s\n", text); fflush(stdout); } else { printf("Shader did not validate successfully.\n"); } return 0; } return 1; } static void render_load_shaders(RenderContext *r) { /* Lighting */ r->lighting_vert = render_load_shader(DATADIR"/shaders/lighting.vert", GL_VERTEX_SHADER); r->lighting_frag = render_load_shader(DATADIR"/shaders/lighting.frag", GL_FRAGMENT_SHADER); r->lighting_program = glCreateProgram(); glAttachShader(r->lighting_program, r->lighting_vert); glAttachShader(r->lighting_program, r->lighting_frag); glLinkProgram(r->lighting_program); render_validate_shader(r->lighting_program); /* Swirlyness */ r->swirly_vert = render_load_shader(DATADIR"/shaders/swirlytron.vert", GL_VERTEX_SHADER); r->swirly_frag = render_load_shader(DATADIR"/shaders/swirlytron.frag", GL_FRAGMENT_SHADER); r->swirly_program = glCreateProgram(); glAttachShader(r->swirly_program, r->swirly_vert); glAttachShader(r->swirly_program, r->swirly_frag); glLinkProgram(r->swirly_program); render_validate_shader(r->swirly_program); } static void render_delete_shaders(RenderContext *r) { glDetachShader(r->lighting_program, r->lighting_frag); glDetachShader(r->lighting_program, r->lighting_vert); glDeleteShader(r->lighting_vert); glDeleteShader(r->lighting_frag); glDeleteProgram(r->lighting_program); } #define HEMI_ROUND_BITS 16 #define HEMI_UP_BITS 8 #define HEMI_NUM_VERTICES (4 * HEMI_ROUND_BITS * HEMI_UP_BITS) #define ADD_VERTEX \ r->hemisphere_v[3*i + 0] = xv; \ r->hemisphere_v[3*i + 1] = yv; \ r->hemisphere_v[3*i + 2] = zv; \ r->hemisphere_n[3*i + 0] = xv; \ r->hemisphere_n[3*i + 1] = yv; \ r->hemisphere_n[3*i + 2] = zv; \ r->hemisphere_t[2*i + 0] = tx; \ r->hemisphere_t[2*i + 1] = ty; \ i++; /* OpenGL initial setup */ RenderContext *render_setup(int width, int height) { RenderContext *r; r = malloc(sizeof(RenderContext)); if ( r == NULL ) return NULL; glewInit(); r->width = width; r->height = height; r->aspect = (GLfloat)width/(GLfloat)height; glClearColor(0.0, 0.0, 0.0, 1.0); glEnable(GL_COLOR_MATERIAL); glColorMaterial(GL_FRONT, GL_AMBIENT_AND_DIFFUSE); glFrontFace(GL_CCW); glEnable(GL_CULL_FACE); glEnable(GL_DEPTH_TEST); glEnable(GL_LIGHTING); glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); if ( GLEW_EXT_framebuffer_object ) { /* Create a small FBO for rendering reflections with */ glGenFramebuffersEXT(1, &r->fbo); glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, r->fbo); /* Add a (texture) colour buffer to the FBO */ glGenTextures(1, &r->fbotex); glBindTexture(GL_TEXTURE_2D, r->fbotex); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, 128, 128, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0); glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, r->fbotex, 0); /* Add a depth buffer to the FBO */ glGenRenderbuffersEXT(1, &r->fbodepth); glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, r->fbodepth); glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_DEPTH_STENCIL_EXT, 128, 128); glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, r->fbodepth); glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_STENCIL_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, r->fbodepth); glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); /* FBO for rendering swirlyness */ glGenFramebuffersEXT(1, &r->swirly_fbo); glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, r->swirly_fbo); /* Add a (texture) colour buffer to the FBO */ glGenTextures(1, &r->swirly_texture); glBindTexture(GL_TEXTURE_2D, r->swirly_texture); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, 128, 128, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0); glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, r->swirly_texture, 0); glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); } else { fprintf(stderr, "EXT_framebuffer_object not supported\n"); } /* Create coordinates for a hemisphere to reuse later */ r->hemisphere_v = malloc(3*HEMI_NUM_VERTICES*sizeof(GLfloat)); r->hemisphere_n = malloc(3*HEMI_NUM_VERTICES*sizeof(GLfloat)); r->hemisphere_t = malloc(2*HEMI_NUM_VERTICES*sizeof(GLfloat)); double step_up = M_PI_2/(double)HEMI_UP_BITS; double step_round = 2*M_PI/(double)HEMI_ROUND_BITS; int is, js; int i = 0; for ( is=0; isnum_textures = 0; /* Load misc texture bits */ texture_load(r, "radioactive"); texture_load(r, "fuel"); return r; } void render_shutdown(RenderContext *r) { render_delete_shaders(r); texture_free_all(r); } static GLenum render_gltype(PrimitiveType type) { switch ( type ) { case PRIMITIVE_QUADS : return GL_QUADS; case PRIMITIVE_TRIANGLES : return GL_TRIANGLES; default : break; } return GL_FALSE; } static int render_model_instance_draw(ModelInstance *instance, Uint32 t, RenderContext *r, int *nvert) { int j; Model *m; GLfloat x, y, z; GLfloat black[] = {0.0, 0.0, 0.0, 1.0}; int wibble; if ( nvert == NULL ) nvert = &wibble; m = instance->model; if ( m == NULL ) return 0; /* No model to draw */ x = instance->x; y = instance->y; z = instance->z; for ( j=0; jnum_primitives; j++ ) { Primitive *p; p = m->primitives[j]; if ( p->attribs & ATTRIB_PULSE ) { float s; s = fabsf(0.4*cosf(t * 0.001)); GLfloat c[] = {s*p->col_r, s*p->col_g, s*p->col_b, 1.0}; glMaterialfv(GL_FRONT, GL_EMISSION, c); glColor3f(0.3, 0.3, 0.3); } else if ( p->attribs & ATTRIB_COLOUR ) { glMaterialfv(GL_FRONT, GL_EMISSION, black); glColor3f(p->col_r, p->col_g, p->col_b); } else { glMaterialfv(GL_FRONT, GL_EMISSION, black); glColor3f(1.0, 1.0, 1.0); } if ( p->attribs & ATTRIB_SHINY ) { GLfloat white[] = {1.0, 1.0, 1.0, 1.0}; glMaterialfv(GL_FRONT, GL_SPECULAR, white); glMaterialf(GL_FRONT, GL_SHININESS, p->shininess); } else { glMaterialfv(GL_FRONT, GL_SPECULAR, black); } if ( p->type != PRIMITIVE_HEMISPHERE ) { /* Location and orientation */ glPushMatrix(); glTranslatef(x, y, z); glRotatef(rad2deg(instance->yaw), 0.0, 0.0, -1.0); /* Minus sign defines +yaw as "right" */ /* Texture */ if ( p->attribs & ATTRIB_SWIRLY ) { glBindTexture(GL_TEXTURE_2D, r->swirly_texture); glEnable(GL_TEXTURE_2D); glUniform1iARB(glGetUniformLocationARB(r->lighting_program, "texture_emits"), 1); } else if ( p->texture != NULL ) { Texture *texture; texture = texture_lookup(r, p->texture); if ( texture != NULL ) { glBindTexture(GL_TEXTURE_2D, texture->texname); glEnable(GL_TEXTURE_2D); glUniform1iARB(glGetUniformLocationARB(r->lighting_program, "texture_enabled"), 1); } else { glUniform1iARB(glGetUniformLocationARB(r->lighting_program, "texture_enabled"), 0); } } else { glUniform1iARB(glGetUniformLocationARB(r->lighting_program, "texture_enabled"), 0); } glBindBufferARB(GL_ARRAY_BUFFER, p->vertices_buffer); glVertexPointer(3, GL_FLOAT, 0, NULL); glBindBufferARB(GL_ARRAY_BUFFER, p->normals_buffer); glNormalPointer(GL_FLOAT, 0, NULL); glBindBufferARB(GL_ARRAY_BUFFER, p->texcoords_buffer); glTexCoordPointer(2, GL_FLOAT, 0, NULL); glDrawArrays(render_gltype(p->type), 0, p->num_vertices); *nvert += p->num_vertices; glBindBufferARB(GL_ARRAY_BUFFER, 0); glDisable(GL_TEXTURE_2D); glPopMatrix(); if ( p->attribs & ATTRIB_SWIRLY ) { glUniform1iARB(glGetUniformLocationARB(r->lighting_program, "texture_emits"), 0); } } else { glPushMatrix(); glTranslatef(x+p->vertices[0], y+p->vertices[1], z+p->vertices[2]); glScalef(p->radius, p->radius, p->radius); glRotatef(rad2deg(instance->yaw), 0.0, 0.0, -1.0); /* Minus sign defines +yaw as "right" */ glEnable(GL_RESCALE_NORMAL); glVertexPointer(3, GL_FLOAT, 0, r->hemisphere_v); glNormalPointer(GL_FLOAT, 0, r->hemisphere_n); glTexCoordPointer(2, GL_FLOAT, 0, r->hemisphere_t); if ( GLEW_EXT_framebuffer_object ) { glBindTexture(GL_TEXTURE_2D, r->fbotex); glEnable(GL_TEXTURE_2D); glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); glUniform1iARB(glGetUniformLocationARB(r->lighting_program, "texture_enabled"), 1); glUniform1iARB(glGetUniformLocationARB(r->lighting_program, "texture_emits"), 1); } glDrawArrays(GL_QUADS, 0, HEMI_NUM_VERTICES); *nvert += HEMI_NUM_VERTICES; glUniform1iARB(glGetUniformLocationARB(r->lighting_program, "texture_emits"), 0); glDisable(GL_TEXTURE_2D); glDisable(GL_RESCALE_NORMAL); glPopMatrix(); } } return 0; } static void render_draw_line(GLfloat x1, GLfloat y1, GLfloat z1, GLfloat x2, GLfloat y2, GLfloat z2) { GLfloat col[] = {0.0, 0.3, 0.0, 1.0}; glMaterialfv(GL_FRONT, GL_EMISSION, col); glColor3f(0.0, 0.0, 0.0); glBegin(GL_LINES); glVertex3f(x1, y1, z1); glVertex3f(x2, y2, z2); glEnd(); } static void render_draw_stuff(Game *game, Uint32 t) { int i; int nvert = 0; glPushClientAttrib(GL_CLIENT_VERTEX_ARRAY_BIT); glEnableClientState(GL_VERTEX_ARRAY); glEnableClientState(GL_NORMAL_ARRAY); glEnableClientState(GL_TEXTURE_COORD_ARRAY); for ( i=0; inum_rooms; i++ ) { Room *room; int j; room = game->rooms[i]; if ( room == NULL ) return; //render_setup_lighting(game, room); for ( j=0; jnum_objects; j++ ) { GLfloat x, y, z; if ( room->objects[j] == NULL ) continue; x = room->rx - game->cur_room_x; y = room->ry - game->cur_room_y; z = room->rz - game->cur_room_z; glPushMatrix(); glTranslatef(10.0*x, 10.0*y, 10.0*z); render_model_instance_draw(room->objects[j], t, game->render, &nvert); glPopMatrix(); } } //printf("%i ***\n", nvert); glPopClientAttrib(); } static void render_setup_lighting(Game *game) { GLfloat pos[4]; GLfloat dir[3]; GLfloat ambient[4]; GLfloat diffuse[4]; GLfloat specular[4]; glEnable(GL_LIGHTING); ambient[0] = 0.01; ambient[1] = 0.01; ambient[2] = 0.01; ambient[3] = 1.0; glLightModelfv(GL_LIGHT_MODEL_AMBIENT, ambient); pos[0] = game->lander->x; pos[1] = game->lander->y; pos[2] = game->lander->z+0.3; pos[3] = 1.0; dir[0] = sinf(game->lander->yaw); dir[1] = cosf(game->lander->yaw); dir[2] = 0.0; dir[3] = 1.0; diffuse[0] = 1.0; diffuse[1] = 1.0; diffuse[2] = 1.0; diffuse[3] = 1.0; specular[0] = 1.0; specular[1] = 1.0; specular[2] = 1.0; specular[3] = 1.0; glLightfv(GL_LIGHT0, GL_POSITION, pos); glLightfv(GL_LIGHT0, GL_DIFFUSE, diffuse); glLightfv(GL_LIGHT0, GL_SPECULAR, specular); glLightfv(GL_LIGHT0, GL_SPOT_DIRECTION, dir); glLightf(GL_LIGHT0, GL_SPOT_CUTOFF, 45.0); glLightf(GL_LIGHT0, GL_SPOT_EXPONENT, 20.0); glLightf(GL_LIGHT0, GL_LINEAR_ATTENUATION, 0.05); glEnable(GL_LIGHT0); pos[0] = -1.0; pos[1] = 0.8; pos[2] = 4.0; pos[3] = 0.0; diffuse[0] = 0.1; diffuse[1] = 0.1; diffuse[2] = 0.1; diffuse[3] = 1.0; specular[0] = 0.01; specular[1] = 0.01; specular[2] = 0.01; specular[3] = 1.0; glLightfv(GL_LIGHT1, GL_POSITION, pos); glLightfv(GL_LIGHT1, GL_DIFFUSE, diffuse); glLightfv(GL_LIGHT1, GL_SPECULAR, specular); glEnable(GL_LIGHT1); } void render_set_wireframe(int wireframe) { if ( wireframe != 0 ) { glPolygonMode(GL_FRONT, GL_LINE); } else { glPolygonMode(GL_FRONT, GL_FILL); } } static void render_draw_2d(RenderContext *r, Game *game) { Texture *texture; GLfloat cr, cg, cb; /* Set up transforms for 2D rendering */ glClear(GL_DEPTH_BUFFER_BIT); glDisable(GL_LIGHTING); glMatrixMode(GL_PROJECTION); glLoadIdentity(); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); glScalef(0.95, 0.95, 1.0); /* Radiation symbol */ texture = texture_lookup(r, "radioactive"); if ( texture != NULL ) { glBindTexture(GL_TEXTURE_2D, texture->texname); glEnable(GL_TEXTURE_2D); glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); } glColor4f(1.0, 1.0, 1.0, PANEL_ALPHA); glBegin(GL_QUADS); glTexCoord2f(0.0, 0.0); glVertex2f(-1.0, -1.0); /* Bottom left */ glTexCoord2f(1.0, 0.0); glVertex2f(-0.9, -1.0); /* Bottom right */ glTexCoord2f(1.0, 1.0); glVertex2f(-0.9, -1.0+0.1*r->aspect); /* Top right */ glTexCoord2f(0.0, 1.0); glVertex2f(-1.0, -1.0+0.1*r->aspect); /* Top left */ glEnd(); glDisable(GL_TEXTURE_2D); /* Radiation meter */ cg = 1.0 - game->radiation; glBegin(GL_QUADS); glColor4f(1.0, 1.0, 0.0, PANEL_ALPHA); glVertex2f(-1.0, -0.8); /* Bottom left */ glVertex2f(-0.9, -0.8); /* Bottom right */ glColor4f(0.8, cg, 0.0, PANEL_ALPHA); glVertex2f(-0.9, -0.8+(1.8*game->radiation)); /* Top right */ glVertex2f(-1.0, -0.8+(1.8*game->radiation)); /* Top left */ glEnd(); /* Fuel symbol */ texture = texture_lookup(r, "fuel"); if ( texture != NULL ) { glBindTexture(GL_TEXTURE_2D, texture->texname); glEnable(GL_TEXTURE_2D); glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); } glColor4f(1.0, 1.0, 1.0, PANEL_ALPHA); glBegin(GL_QUADS); glTexCoord2f(0.0, 0.0); glVertex2f(0.9, -1.0); /* Bottom left */ glTexCoord2f(1.0, 0.0); glVertex2f(1.0, -1.0); /* Bottom right */ glTexCoord2f(1.0, 1.0); glVertex2f(1.0, -1.0+0.1*r->aspect); /* Top right */ glTexCoord2f(0.0, 1.0); glVertex2f(0.9, -1.0+0.1*r->aspect); /* Top left */ glEnd(); glDisable(GL_TEXTURE_2D); /* Fuel meter */ cr = 1.0 - game->fuel; cg = game->fuel; cb = 0.2 + 0.1*game->fuel; glBegin(GL_QUADS); glColor4f(1.0, 0.0, 0.2, PANEL_ALPHA); glVertex2f(0.9, -0.8); /* Bottom left */ glVertex2f(1.0, -0.8); /* Bottom right */ glColor4f(cr, cg, cb, PANEL_ALPHA); glVertex2f(1.0, -0.8+(1.8*game->fuel)); /* Top right */ glVertex2f(0.9, -0.8+(1.8*game->fuel)); /* Top left */ glEnd(); } void render_draw(Game *game, Uint32 t) { RenderContext *r; r = game->render; if ( GLEW_EXT_framebuffer_object ) { /* First pass: Looking upwards */ glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, r->fbo); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glViewport(0, 0, 256, 256); glMatrixMode(GL_PROJECTION); glLoadIdentity(); gluPerspective(70.0, 1.0, 0.1, 80.0); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); gluLookAt(game->lander->x, game->lander->y, game->lander->z, game->lander->x, game->lander->y, game->lander->z+10.0, sqrtf(2.0)*sinf(game->lander->yaw), sqrtf(2.0)*cosf(game->lander->yaw), 0.0); render_setup_lighting(game); GLfloat amb[] = { 0.1, 0.1, 0.1, 1.0 }; glLightModelfv(GL_LIGHT_MODEL_AMBIENT, amb); render_draw_stuff(game, t); /* Render some swirlyness */ glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, r->swirly_fbo); glClear(GL_COLOR_BUFFER_BIT); glViewport(0, 0, 128, 128); glUseProgramObjectARB(r->swirly_program); glUniform1fARB(glGetUniformLocationARB(game->render->swirly_program, "time"), t); glMatrixMode(GL_PROJECTION); glLoadIdentity(); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); glBegin(GL_QUADS); glVertex2f(-1.0, -1.0); glVertex2f(+1.0, -1.0); glVertex2f(+1.0, +1.0); glVertex2f(-1.0, +1.0); glEnd(); glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); } /* Second pass: Main view */ glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glViewport(0, 0, r->width, r->height); glMatrixMode(GL_PROJECTION); glLoadIdentity(); gluPerspective(50.0, (GLfloat)r->width/(GLfloat)r->height, 0.1, 100.0); /* Depth buffer 10cm to 100m */ glMatrixMode(GL_MODELVIEW); glLoadIdentity(); gluLookAt(game->lander->x-(game->view_dist*sinf(game->lander->yaw)*cosf(game->view_angle)), game->lander->y-(game->view_dist*cosf(game->lander->yaw)*cosf(game->view_angle)), game->lander->z+(game->view_dist*sinf(game->view_angle)), game->lander->x, game->lander->y, game->lander->z, sqrtf(2.0)*sinf(game->lander->yaw)*sinf(game->view_angle), sqrtf(2.0)*cosf(game->lander->yaw)*sinf(game->view_angle), sqrtf(2.0)*cosf(game->view_angle)); glUseProgramObjectARB(r->lighting_program); glUniform1iARB(glGetUniformLocationARB(game->render->lighting_program, "texture"), 0); glUniform1iARB(glGetUniformLocationARB(game->render->lighting_program, "texture_only"), 0); glUniform1iARB(glGetUniformLocationARB(game->render->lighting_program, "texture_enabled"), 1); glUniform1iARB(glGetUniformLocationARB(game->render->lighting_program, "fill_light_enabled"), 0); render_setup_lighting(game); render_draw_stuff(game, t); /* Finally, draw the lander */ GLfloat pos[] = { -1.0, 0.8, 4.0, 0.0 }; GLfloat diffuse[] = { 0.4, 0.4, 0.4, 1.0 }; GLfloat specular[] = { 0.1, 0.1, 0.1, 1.0 }; glLightfv(GL_LIGHT2, GL_POSITION, pos); glLightfv(GL_LIGHT2, GL_DIFFUSE, diffuse); glLightfv(GL_LIGHT2, GL_SPECULAR, specular); glEnable(GL_LIGHT2); glPushClientAttrib(GL_CLIENT_VERTEX_ARRAY_BIT); glEnableClientState(GL_VERTEX_ARRAY); glEnableClientState(GL_NORMAL_ARRAY); glEnableClientState(GL_TEXTURE_COORD_ARRAY); render_model_instance_draw(game->lander, t, r, NULL); glPopClientAttrib(); glUniform1iARB(glGetUniformLocationARB(game->render->lighting_program, "texture_enabled"), 0); render_draw_line(game->lander->x, game->lander->y, game->lander->z, game->lander->x, game->lander->y, game->lander->z-200.0); glDisable(GL_LIGHT2); glUseProgramObjectARB(0); render_draw_2d(r, game); SDL_GL_SwapBuffers(); }