/* * render.c * * Render the scene * * Copyright (c) 2008 Thomas White * * This file is part of Thrust3D - a silly game * * Thrust3D is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * Thrust3D is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Thrust3D. If not, see . * */ #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" #include "render-text.h" #include "shaderutils.h" #define PANEL_ALPHA 0.3 static void render_load_shaders(RenderContext *r) { /* Lighting */ r->lighting_vert = shaderutils_load_shader(DATADIR"/shaders/lighting.vert", GL_VERTEX_SHADER); r->lighting_frag = shaderutils_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); shaderutils_link_program(r->lighting_program); shaderutils_validate_program(r->lighting_program); /* Fill-in light */ r->fill_vert = shaderutils_load_shader(DATADIR"/shaders/fill-light.vert", GL_VERTEX_SHADER); r->fill_frag = shaderutils_load_shader(DATADIR"/shaders/fill-light.frag", GL_FRAGMENT_SHADER); r->fill_program = glCreateProgram(); glAttachShader(r->fill_program, r->fill_vert); glAttachShader(r->fill_program, r->fill_frag); shaderutils_link_program(r->fill_program); shaderutils_validate_program(r->fill_program); /* Swirlyness */ r->swirly_vert = shaderutils_load_shader(DATADIR"/shaders/swirlytron.vert", GL_VERTEX_SHADER); r->swirly_frag = shaderutils_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); shaderutils_link_program(r->swirly_program); shaderutils_validate_program(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); glDetachShader(r->fill_program, r->fill_frag); glDetachShader(r->fill_program, r->fill_vert); glDeleteShader(r->fill_vert); glDeleteShader(r->fill_frag); glDeleteProgram(r->fill_program); glDetachShader(r->swirly_program, r->swirly_frag); glDetachShader(r->swirly_program, r->swirly_vert); glDeleteShader(r->swirly_vert); glDeleteShader(r->swirly_frag); glDeleteProgram(r->swirly_program); } /* OpenGL initial setup */ RenderContext *render_setup(int width, int height, int disable_vbos, int disable_fbos, int disable_shaders) { RenderContext *r; r = malloc(sizeof(RenderContext)); if ( r == NULL ) return NULL; glewInit(); if ( disable_vbos == 0 ) { if ( GLEW_VERSION_1_5 || GLEW_ARB_vertex_buffer_object ) { r->vbos = 1; } else { r->vbos = 0; fprintf(stderr, "Vertex buffer objects are not supported by your graphics card or driver\n"); } } else { printf("The use of vertex buffer objects has been disabled at your request.\n"); r->vbos = 0; } if ( r->vbos == 0 ) { fprintf(stderr, " -> Geometry performance may be less than optimal.\n"); } if ( disable_fbos == 0 ) { if ( GLEW_EXT_framebuffer_object ) { r->fbos = 1; } else { r->fbos = 0; fprintf(stderr, "Framebuffer objects are not supported by your graphics card or driver\n"); } } else { printf("The use of framebuffer objects has been disabled at your request.\n"); r->fbos = 0; } if ( r->fbos == 0 ) { fprintf(stderr, " -> Reflections and GPU dynamic textures disabled.\n"); } if ( disable_shaders == 0 ) { if ( ( GLEW_ARB_vertex_shader && GLEW_ARB_fragment_shader && GLEW_ARB_shader_objects && GLEW_ARB_shading_language_100 ) || GLEW_VERSION_2_0 ) { r->shaders = 1; } else { r->shaders = 0; fprintf(stderr, "Shaders are not supported by your graphics card or driver\n"); } } else { printf("The use of shaders has been disabled at your request.\n"); r->shaders = 0; } if ( r->shaders == 0 ) { fprintf(stderr, " -> Per-fragment lighting and GPU dynamic textures disabled.\n"); } if ( GLEW_EXT_timer_query ) { r->timer_queries = 1; } else { r->timer_queries = 0; fprintf(stderr, "Timer queries are not supported by your graphics card or driver\n"); fprintf(stderr, " -> A default estimated time will be used. Framerate may be lower than it should.\n"); } 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); glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER, 1); if ( r->fbos ) { /* 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, 64, 64, 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); } if ( r->shaders ) render_load_shaders(r); r->num_textures = 0; /* Load misc texture bits */ texture_load(r, "radioactive"); texture_load(r, "fuel"); texture_load(r, "placeholder"); render_text_setup(r); return r; } void render_shutdown(RenderContext *r) { if ( r->shaders ) 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 void render_placeholder_texture(RenderContext *r) { Texture *texture; texture = texture_lookup(r, "placeholder"); if ( texture != NULL ) { glBindTexture(GL_TEXTURE_2D, texture->texname); glEnable(GL_TEXTURE_2D); } else { fprintf(stderr, "Couldn't find placeholder texture!\n"); } } static int render_model_instance_draw(ModelInstance *instance, RenderContext *r, Game *g, int *nvert, GLfloat alpha) { int j; Model *m; GLfloat x, y, z; GLfloat black[] = {0.0, 0.0, 0.0, 1.0}; int wibble; if ( r->shaders ) shaderutils_setunf(r->lighting_program, "alpha", alpha); 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) && !(p->attribs & ATTRIB_SWIRLY)) || ((p->attribs & ATTRIB_SWIRLY) && !(r->fbos && r->shaders)) ) { float s; s = fabsf(0.4*cosf(g->time * 0.001)); GLfloat c[] = {s*p->col_r, s*p->col_g, s*p->col_b, 1.0}; glMaterialfv(GL_FRONT, GL_EMISSION, c); glColor4f(0.3, 0.3, 0.3, alpha); } else if ( (p->attribs & ATTRIB_COLOUR) && !(p->attribs & ATTRIB_SWIRLY) ) { glMaterialfv(GL_FRONT, GL_EMISSION, black); glColor4f(p->col_r, p->col_g, p->col_b, alpha); } else { glMaterialfv(GL_FRONT, GL_EMISSION, black); glColor4f(1.0, 1.0, 1.0, alpha); } /* Set specular colour and shininess if required */ if ( p->attribs & ATTRIB_SHINY ) { GLfloat spec[4]; if ( p->attribs & ATTRIB_COLSPEC ) { spec[0] = p->colspec; spec[1] = p->colspec; spec[2] = p->colspec; spec[3] = 1.0; } else { spec[0] = 1.0; spec[1] = 1.0; spec[2] = 1.0; spec[3] = 1.0; } glMaterialfv(GL_FRONT, GL_SPECULAR, spec); glMaterialf(GL_FRONT, GL_SHININESS, p->shininess); if ( r->shaders ) { shaderutils_setunf(r->lighting_program, "shininess", p->shininess); shaderutils_setunf(r->fill_program, "shininess", p->shininess); } } else { glMaterialfv(GL_FRONT, GL_SPECULAR, black); } /* 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 ) { if ( r->fbos && r->shaders ) { glBindTexture(GL_TEXTURE_2D, r->swirly_texture); glEnable(GL_TEXTURE_2D); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); shaderutils_setuni(r->lighting_program, "texture_emits", 1); } else { if ( r->shaders ) render_placeholder_texture(r); /* else don't glEnable() texturing */ } } 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); glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); if ( r->shaders && texture->has_normals ) { glActiveTexture(GL_TEXTURE1); glBindTexture(GL_TEXTURE_2D, texture->normalmap); shaderutils_setuni(r->lighting_program, "has_normals", 1); glActiveTexture(GL_TEXTURE0); } } else { if ( r->shaders ) render_placeholder_texture(r); } } else { if ( r->shaders ) render_placeholder_texture(r); } if ( r->vbos ) { glBindBuffer(GL_ARRAY_BUFFER, p->vertices_buffer); glVertexPointer(3, GL_FLOAT, 0, NULL); glBindBuffer(GL_ARRAY_BUFFER, p->normals_buffer); glNormalPointer(GL_FLOAT, 0, NULL); glBindBuffer(GL_ARRAY_BUFFER, p->texcoords_buffer); glTexCoordPointer(2, GL_FLOAT, 0, NULL); glBindBuffer(GL_ARRAY_BUFFER, 0); } else { glVertexPointer(3, GL_FLOAT, 0, p->vertices); glNormalPointer(GL_FLOAT, 0, p->normals); glTexCoordPointer(2, GL_FLOAT, 0, p->texcoords); } glDrawArrays(render_gltype(p->type), 0, p->num_vertices); *nvert += p->num_vertices; glDisable(GL_TEXTURE_2D); if ( r->shaders ) shaderutils_setuni(r->lighting_program, "has_normals", 0); glPopMatrix(); if ( p->attribs & ATTRIB_SWIRLY ) { if ( r->shaders ) shaderutils_setuni(r->lighting_program, "texture_emits", 0); } } return 0; } static void render_draw_line(GLfloat x1, GLfloat y1, GLfloat z1, GLfloat x2, GLfloat y2, GLfloat z2) { GLfloat col[] = {0.0, 1.0, 0.0, 1.0}; glMaterialfv(GL_FRONT, GL_EMISSION, col); glColor3f(0.0, 1.0, 0.0); glBegin(GL_LINES); glVertex3f(x1, y1, z1); glVertex3f(x2, y2, z2); glEnd(); } static void render_draw_stuff(Game *game, GLfloat alpha) { 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], game->render, game, &nvert, alpha); glPopMatrix(); } } //printf("%i ***\n", nvert); glPopClientAttrib(); } static void render_setup_lighting(Game *game) { GLfloat pos[4]; GLfloat dir[3]; GLfloat ambient[4] = { 0.0, 0.0, 0.0, 1.0 }; GLfloat diffuse[4]; GLfloat specular[4]; glEnable(GL_LIGHTING); /* Set a very dull background */ ambient[0] = 0.07; ambient[1] = 0.07; ambient[2] = 0.07; ambient[3] = 1.0; glLightModelfv(GL_LIGHT_MODEL_AMBIENT, ambient); /* Lander craft's headlight */ pos[0] = game->lander->x; pos[1] = game->lander->y; pos[2] = game->lander->z+0.3; pos[3] = 1.0; glLightfv(GL_LIGHT0, GL_POSITION, pos); dir[0] = sinf(game->lander->yaw); dir[1] = cosf(game->lander->yaw); dir[2] = 0.0; 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_CONSTANT_ATTENUATION, 1.0); glLightf(GL_LIGHT0, GL_LINEAR_ATTENUATION, 0.02); glLightf(GL_LIGHT0, GL_QUADRATIC_ATTENUATION, 0.005); /* Headlight colours */ ambient[0] = 0.2; ambient[1] = 0.2; ambient[2] = 0.2; glLightfv(GL_LIGHT0, GL_AMBIENT, ambient); /* Initialised to zero above */ diffuse[0] = 1.0; diffuse[1] = 1.0; diffuse[2] = 1.0; diffuse[3] = 1.0; glLightfv(GL_LIGHT0, GL_DIFFUSE, diffuse); specular[0] = 1.0; specular[1] = 1.0; specular[2] = 1.0; specular[3] = 1.0; glLightfv(GL_LIGHT0, GL_SPECULAR, specular); glEnable(GL_LIGHT0); /* A very dim fill-in light. Adds a tiny amount of shape to things, and lifts the floor a little */ ambient[0] = 0.0; ambient[1] = 0.0; ambient[2] = 0.0; glLightfv(GL_LIGHT1, GL_AMBIENT, ambient); /* Initialised to zero above */ pos[0] = -1.0; pos[1] = 0.8; pos[2] = 4.0; pos[3] = 0.0; glLightfv(GL_LIGHT1, GL_POSITION, pos); diffuse[0] = 0.05; diffuse[1] = 0.05; diffuse[2] = 0.05; diffuse[3] = 1.0; glLightfv(GL_LIGHT1, GL_DIFFUSE, diffuse); specular[0] = 0.0; specular[1] = 0.0; specular[2] = 0.0; specular[3] = 1.0; glLightfv(GL_LIGHT1, GL_SPECULAR, specular); glEnable(GL_LIGHT1); /* A fill-in light, only used on its own, to light the lander craft itself */ glLightfv(GL_LIGHT2, GL_AMBIENT, ambient); /* Initialised to zero above */ pos[0] = 0.0; pos[1] = 0.0; pos[2] = 4.0; pos[3] = 0.0; glLightfv(GL_LIGHT2, GL_POSITION, pos); diffuse[0] = 0.3; diffuse[1] = 0.3; diffuse[2] = 0.3; diffuse[3] = 1.0; glLightfv(GL_LIGHT2, GL_DIFFUSE, diffuse); specular[0] = 1.0; specular[1] = 1.0; specular[2] = 1.0; specular[3] = 1.0; glLightfv(GL_LIGHT2, GL_SPECULAR, specular); } 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.7*game->radiation)); /* Top right */ glVertex2f(-1.0, -0.8+(1.7*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(); Room *room; room = game_find_room(game, game->cur_room_x, game->cur_room_y, game->cur_room_z); if ( room != NULL ) { if ( room->comment != NULL ) render_text_write(-1.0, 1.0, room->comment, r); } } void render_draw(Game *game) { RenderContext *r; GLfloat amb[] = { 0.0, 0.0, 0.0, 1.0 }; GLfloat fx, fy, fz; GLfloat fxt, fyt, fzt; r = game->render; if ( r->timer_queries && game->query_this_frame ) { glGenQueries(1, &game->timer_query); glBeginQuery(GL_TIME_ELAPSED_EXT, game->timer_query); } if ( r->fbos ) { /* Render some swirlyness */ glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, r->swirly_fbo); glClear(GL_COLOR_BUFFER_BIT); glViewport(0, 0, 64, 64); if ( r->shaders ) { GLfloat rrb = 0.0; glUseProgram(r->swirly_program); shaderutils_setunf(r->swirly_program, "time", game->time); shaderutils_setuni(r->swirly_program, "landed", game->lander->recharging); if ( game->lander->recharging ) { /* Fade in */ rrb = fminf(((GLfloat)game->time-game->time_of_landing_event)/1500.0, 1.0); shaderutils_setuni(r->swirly_program, "rechargeripple", 1); } else if ( game->time_of_landing_event - game->time < 750 ) { /* Fade out */ rrb = fmaxf(1.0 - ((GLfloat)game->time-game->time_of_landing_event)/750.0, 0.0); shaderutils_setuni(r->swirly_program, "rechargeripple", 1); } else { shaderutils_setuni(r->swirly_program, "rechargeripple", 0); } shaderutils_setunf(r->swirly_program, "rrb", rrb); shaderutils_setun2f(r->swirly_program, "lander", game->platform_rel_x, game->platform_rel_y); } /* else this is all a little pointless... */ 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); if ( r->shaders ) glUseProgram(0); } /* 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(); fx = 0.0; fy = -game->view_dist; fz = 0.0; fxt = fx; fyt = fy; fzt = fz; fx = fxt; fy = fyt*cos(game->view_angle) + fzt*sin(game->view_angle); fz = fyt*sin(game->view_angle) + fzt*cos(game->view_angle); fxt = fx; fyt = fy; fzt = fz; fx = fxt*cos(game->view_yaw+game->lander->yaw) + fyt*sin(game->view_yaw+game->lander->yaw); fy = -fxt*sin(game->view_yaw+game->lander->yaw) + fyt*cos(game->view_yaw+game->lander->yaw); fz = fzt; fx += game->lander->x; fy += game->lander->y; fz += game->lander->z; gluLookAt(fx, fy, fz, game->lander->x, game->lander->y, game->lander->z, 0.0, 0.0, 1.0); if ( r->shaders ) { glUseProgram(r->lighting_program); shaderutils_setuni(r->lighting_program, "texture", 0); /* GL_TEXTURE0 */ shaderutils_setuni(r->lighting_program, "normalmap", 1); /* GL_TEXTURE1 */ shaderutils_setuni(r->lighting_program, "texture_only", 0); shaderutils_setuni(r->lighting_program, "has_normals", 0); } render_setup_lighting(game); amb[0] = 0.02; amb[1] = 0.02; amb[2] = 0.02; glLightModelfv(GL_LIGHT_MODEL_AMBIENT, amb); render_draw_stuff(game, 1.0); /* Draw the lander */ glEnable(GL_LIGHT2); glDisable(GL_LIGHT0); glDisable(GL_LIGHT1); glPushClientAttrib(GL_CLIENT_VERTEX_ARRAY_BIT); glEnableClientState(GL_VERTEX_ARRAY); glEnableClientState(GL_NORMAL_ARRAY); glEnableClientState(GL_TEXTURE_COORD_ARRAY); if ( r->shaders ) glUseProgram(r->fill_program); render_model_instance_draw(game->lander, r, game, NULL, 1.0); glPopClientAttrib(); if ( r->shaders ) glUseProgram(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); /* Back faces (done last to make blending work properly) */ /* Shaders still disabled (speeds this up a lot) */ glFrontFace(GL_CW); glPolygonOffset(1.0, 1.0); glEnable(GL_POLYGON_OFFSET_FILL); render_setup_lighting(game); amb[0] = 0.1; amb[1] = 0.1; amb[2] = 0.1; glLightModelfv(GL_LIGHT_MODEL_AMBIENT, amb); render_draw_stuff(game, 0.5); glDisable(GL_POLYGON_OFFSET_FILL); glFrontFace(GL_CCW); render_draw_2d(r, game); if ( r->timer_queries && game->query_this_frame) glEndQuery(GL_TIME_ELAPSED_EXT); SDL_GL_SwapBuffers(); if ( r->timer_queries && !game->query_this_frame ) { GLint available; glGetQueryObjectiv(game->timer_query, GL_QUERY_RESULT_AVAILABLE, &available); if ( available ) { GLuint64EXT time_to_render; glGetQueryObjectui64vEXT(game->timer_query, GL_QUERY_RESULT, &time_to_render); game->time_render = time_to_render / 1000; /* Convert ns to us */ game->query_this_frame = 1; glDeleteQueries(1, &game->timer_query); } } else { game->query_this_frame = 0; } }