/* * render.c * * Render the scene * * (c) 2008 Thomas White * * thrust3d - a silly game * */ #ifdef HAVE_CONFIG_H #include #endif #define GL_GLEXT_PROTOTYPES 1 #include #include #include #include #include #include #include "model.h" #include "game.h" #include "render.h" #include "texture.h" #include "utils.h" /* Utility function to load and compile a shader, checking the info log */ static GLhandleARB render_load_shader(const char *filename, GLenum type) { GLhandleARB shader; char text[4096]; size_t len; FILE *fh; int l; 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 GLcharARB *source = text; shader = glCreateShaderObjectARB(type); glShaderSourceARB(shader, 1, &source, NULL); glCompileShaderARB(shader); glGetInfoLogARB(shader, 4095, &l, text); if ( l > 0 ) { printf("%s\n", text); fflush(stdout); } return shader; } static void render_load_shaders(RenderContext *ctx) { ctx->lighting_vert = render_load_shader(DATADIR"/shaders/lighting.vert", GL_VERTEX_SHADER_ARB); ctx->lighting_frag = render_load_shader(DATADIR"/shaders/lighting.frag", GL_FRAGMENT_SHADER_ARB); ctx->lighting_program = glCreateProgramObjectARB(); glAttachObjectARB(ctx->lighting_program, ctx->lighting_vert); glAttachObjectARB(ctx->lighting_program, ctx->lighting_frag); glLinkProgramARB(ctx->lighting_program); } static void render_delete_shaders(RenderContext *ctx) { glDetachObjectARB(ctx->lighting_program, ctx->lighting_frag); glDetachObjectARB(ctx->lighting_program, ctx->lighting_vert); glDeleteObjectARB(ctx->lighting_vert); glDeleteObjectARB(ctx->lighting_frag); glDeleteObjectARB(ctx->lighting_program); } /* OpenGL initial setup */ RenderContext *render_setup() { RenderContext *ctx; ctx = malloc(sizeof(RenderContext)); if ( ctx == NULL ) return NULL; glClearColor(0.0, 0.0, 0.0, 1.0); glViewport(0, 0, 640, 480); glMatrixMode(GL_PROJECTION); glLoadIdentity(); gluPerspective(50.0, 640.0/480.0, 0.1, 100.0); /* Depth buffer 10cm to 100m */ 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); glEnableClientState(GL_VERTEX_ARRAY); glEnableClientState(GL_NORMAL_ARRAY); glEnableClientState(GL_TEXTURE_COORD_ARRAY); render_load_shaders(ctx); ctx->num_textures = 0; ctx->frames = 0; ctx->t_fps = SDL_GetTicks(); ctx->fps = 0; return ctx; } void render_shutdown(RenderContext *ctx) { render_delete_shaders(ctx); texture_free_all(ctx); } static int render_model_instance_draw(ModelInstance *instance, Uint32 t, RenderContext *ctx) { int j; Model *m; GLfloat x, y, z; GLfloat black[] = {0.0, 0.0, 0.0}; 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(cosf(t * 0.001)); GLfloat c[] = {s*p->col_r, s*p->col_g, s*p->col_b}; glMaterialfv(GL_FRONT, GL_EMISSION, c); glColor3f(0.3, 0.3, 0.3); glMaterialfv(GL_FRONT, GL_SPECULAR, black); } else if ( p->attribs & ATTRIB_COLOUR ) { glMaterialfv(GL_FRONT, GL_EMISSION, black); glMaterialfv(GL_FRONT, GL_SPECULAR, black); glColor3f(p->col_r, p->col_g, p->col_b); } else { glMaterialfv(GL_FRONT, GL_EMISSION, black); glMaterialfv(GL_FRONT, GL_SPECULAR, black); glColor3f(1.0, 1.0, 1.0); } /* 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->texture != NULL ) { Texture *texture; texture = texture_lookup(ctx, 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); } } glVertexPointer(3, GL_FLOAT, 0, p->vertices); glNormalPointer(GL_FLOAT, 0, p->normals); glTexCoordPointer(2, GL_FLOAT, 0, p->texcoords); glDrawArrays(p->type, 0, p->num_vertices); glPopMatrix(); glDisable(GL_TEXTURE_2D); } return 0; } #if 0 static void render_configure_light(int *ilightp, Light light, Room *room, Game *game) { GLfloat x, y, z; int ilight; GLfloat pos[4]; GLfloat diffuse[] = { 1.0, 1.0, 1.0, 1.0 }; GLfloat specular[] = { 1.0, 1.0, 1.0, 1.0 }; ilight = *ilightp; 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); pos[0] = light.x; pos[1] = light.y; pos[2] = light.z; pos[3] = 1.0; if ( ilight < GL_MAX_LIGHTS ) { glLightfv(GL_LIGHT0+ilight, GL_POSITION, pos); glLightfv(GL_LIGHT0+ilight, GL_DIFFUSE, diffuse); glLightfv(GL_LIGHT0+ilight, GL_SPECULAR, specular); glLightf(GL_LIGHT0+ilight, GL_LINEAR_ATTENUATION, 0.01); glEnable(GL_LIGHT0+ilight); ilight++; } glPopMatrix(); *ilightp = ilight; } static void render_setup_lighting(Game *game, Room *room_current) { int i, ilight; GLfloat ambient[4]; /* Start with a blackout */ for ( ilight=0; ilightnum_lights; i++ ) { render_configure_light(&ilight, room_current->lights[i], room_current, game); } /* Lights in rooms connected to this one */ for ( i=0; inum_connected; i++ ) { Room *room; int j; room = game_find_room(game, room_current->connected[i].rx, room_current->connected[i].ry, room_current->connected[i].rz); if ( room == NULL ) continue; /* Shouldn't happen... */ for ( j=0; jnum_lights; j++ ) { render_configure_light(&ilight, room->lights[j], room, game); } } ambient[0] = 0.3; ambient[1] = 0.3; ambient[2] = 0.3; ambient[3] = 1.0; //ambient[0] = 1.0; ambient[1] = 1.0; ambient[2] = 1.0; ambient[3] = 1.0; glLightModelfv(GL_LIGHT_MODEL_AMBIENT, ambient); } #endif void render_draw(Game *game) { int i; Uint32 t; t = SDL_GetTicks(); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); gluLookAt(game->lander->x-(1.5*sinf(game->lander->yaw)*cosf(game->view_angle)), game->lander->y-(1.5*cosf(game->lander->yaw)*cosf(game->view_angle)), game->lander->z+(1.5*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)); //gluLookAt(game->lander->x-(1.5*sinf(game->lander->yaw)), // game->lander->y-(1.5*cosf(game->lander->yaw)), 1.5+game->lander->z, // game->lander->x, game->lander->y, game->lander->z, // sqrt(2.0)*sinf(game->lander->yaw), sqrtf(2.0)*cosf(game->lander->yaw), sqrtf(2.0)); //gluLookAt(0.0, -250.0, -495.0+250.0, // 0.0, 0.0, -495.0, // 0.0, sqrtf(2.0), sqrtf(2.0)); GLfloat pos[] = {-1.0, -1.0, 1.0, 0.0}; GLfloat ambient[4]; GLfloat diffuse[] = {0.8, 0.8, 0.8, 1.0}; GLfloat specular[] = {0.8, 0.8, 0.8, 1.0}; ambient[0] = 0.3; ambient[1] = 0.3; ambient[2] = 0.3; ambient[3] = 1.0; glLightModelfv(GL_LIGHT_MODEL_AMBIENT, ambient); glLightfv(GL_LIGHT0, GL_POSITION, pos); glLightfv(GL_LIGHT0, GL_DIFFUSE, diffuse); glLightfv(GL_LIGHT0, GL_SPECULAR, specular); glEnable(GL_LIGHT0); /* Draw the objects */ //glUniform1iARB(glGetUniformLocationARB(game->render->lighting_program, "texture"), 0); //glUseProgramObjectARB(game->render->lighting_program); 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); glPopMatrix(); } } /* Finally, the lander */ render_model_instance_draw(game->lander, t, game->render); //glUseProgramObjectARB(0); SDL_GL_SwapBuffers(); game->render->frames++; if ( t - game->render->t_fps > 1000 ) { game->render->fps = (1000*game->render->frames) / (t - game->render->t_fps); game->render->t_fps = t; game->render->frames = 0; } }