#include #include #include #include #include #include #include #include "common.h" #include "game.h" #include "Explosion.h" #include "Schedule.h" #include "oglfont.h" #include "Time.h" #include "network.h" GLUquadricObj *quadratic; Explosion explosion; void key_callback(int key, int state) { } void setup_light() { GLfloat LightAmbient[] = { 0.5f, 0.5f, 0.5f, 1.0f }; GLfloat LightDiffuse[] = { 0.5f, 0.5f, 0.5f, 1.0f }; GLfloat LightPosition[] = { 1.0f, 1.0f, 1.0f, 0.0f }; // setup directional light glLightfv(GL_LIGHT0, GL_AMBIENT, LightAmbient); glLightfv(GL_LIGHT0, GL_DIFFUSE, LightDiffuse); glLightfv(GL_LIGHT0, GL_POSITION, LightPosition); glEnable( GL_LIGHT0); glEnable( GL_LIGHTING); } void setup_opengl() { // Open OpenGL window if (!glfwOpenWindow(640, 480, 0, 0, 0, 0, 0, 0, GLFW_WINDOW)) { fprintf(stderr, "Failed to open GLFW window\n"); glfwTerminate(); exit(EXIT_FAILURE); } //glfwDisable(GLFW_MOUSE_CURSOR); glfwSetWindowTitle("Gremlin Lan Party Game"); glfwSetKeyCallback(key_callback); // Enable sticky keys glfwEnable(GLFW_STICKY_KEYS); // general settings glShadeModel( GL_SMOOTH); glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST); glEnable( GL_CULL_FACE); // setup depth buffer glClearDepth(1.0f); glEnable( GL_DEPTH_TEST); glDepthFunc( GL_LEQUAL); // Enable vertical sync (on cards that support it) glfwSwapInterval(0); } void draw_team(team_t *team) { size_t i = 0; glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, team->color); glMatrixMode( GL_MODELVIEW); glPushMatrix(); glTranslated(team->x, team->y, team->z); gluSphere(quadratic, 50.f, 32, 32); glPopMatrix(); } void draw_player(player_t *player) { if (player->status == 0) return; glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, player->team->color); glMatrixMode( GL_MODELVIEW); glPushMatrix(); glTranslated(player->x, player->y, player->z); gluSphere(quadratic, 10.f, 32, 32); glPopMatrix(); } void draw_bomb(bomb_t *bomb) { if (bomb->status != 1) return; GLfloat red[] = { 1.0f, 0.0f, 0.0f, 1.0f }; glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, red); glMatrixMode( GL_MODELVIEW); glPushMatrix(); glTranslated(bomb->x, bomb->y, bomb->z); gluSphere(quadratic, 3.f, 4, 4); glPopMatrix(); } void draw_point(point_t *point) { if (point->status == 0) return; GLfloat red[] = { 0.0f, 0.0f, 1.0f, 1.0f }; glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, red); glMatrixMode( GL_MODELVIEW); glPushMatrix(); glTranslated(point->x, point->y, point->z); gluSphere(quadratic, 3.f, 12, 12); glPopMatrix(); } void setup_explosion() { // Loads particle texture GLuint textures[5]; glGenTextures(5, textures); glBindTexture(GL_TEXTURE_2D, textures[0]); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glfwLoadTexture2D("data/explosion/explosion.tga", GLFW_ALPHA_MAP_BIT); glBindTexture(GL_TEXTURE_2D, textures[1]); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glfwLoadTexture2D("data/explosion/flash.tga", 0); glBindTexture(GL_TEXTURE_2D, textures[2]); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glfwLoadTexture2D("data/explosion/spark.tga", 0); glBindTexture(GL_TEXTURE_2D, textures[3]); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glfwLoadTexture2D("data/explosion/point.tga", GLFW_ALPHA_MAP_BIT); glBindTexture(GL_TEXTURE_2D, textures[4]); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glfwLoadTexture2D("data/explosion/wave.tga", 0); explosion.initialize(textures[0], textures[1], textures[2], textures[3], textures[4]); } void explosion_callback(double x, double y, double z) { explosion.add(x, y, z); } GLuint wallTex = 0; void draw_box() { if (wallTex == 0) { glGenTextures(1, &wallTex); glBindTexture(GL_TEXTURE_2D, wallTex); glEnable( GL_TEXTURE_2D); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); glfwLoadTexture2D("data/wall.tga", GLFW_BUILD_MIPMAPS_BIT); } else { glBindTexture(GL_TEXTURE_2D, wallTex); glEnable( GL_TEXTURE_2D); } GLfloat red[] = { 1.0f, 1.0f, 1.0f, 1.0f }; glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, red); // Enable/Disable features glPushAttrib( GL_ENABLE_BIT); glEnable( GL_TEXTURE_2D); //glDisable( GL_DEPTH_TEST); // glEnable( GL_LIGHTING); // glDisable( GL_BLEND); glMatrixMode( GL_MODELVIEW); glPushMatrix(); glTranslated(2000.0, 0.0, 0.0); //glScaled(5000.0f, 5000.0f, 5000.0f); float s = 3000.0f, t = 10.0f; // Just in case we set all vertices to white. glColor4f(1, 1, 1, 1); // Render the front quad glBegin( GL_QUADS); glTexCoord2f(0, t); glNormal3f(0.0, 0.0, 1.0); glVertex3f(-s, s, -s); glTexCoord2f(0, 0); glNormal3f(0.0, 0.0, 1.0); glVertex3f(-s, -s, -s); glTexCoord2f(t, 0); glNormal3f(0.0, 0.0, 1.0); glVertex3f(s, -s, -s); glTexCoord2f(t, t); glNormal3f(0.0, 0.0, 1.0); glVertex3f(s, s, -s); glEnd(); // Render the left quad glBegin(GL_QUADS); glTexCoord2f(0, 0); glVertex3f(s, -s, s); glTexCoord2f(0, t); glVertex3f(s, s, s); glTexCoord2f(t, t); glVertex3f(s, s, -s); glTexCoord2f(t, 0); glVertex3f(s, -s, -s); glEnd(); // Render the back quad // glBindTexture(GL_TEXTURE_2D, _skybox[2]); glBegin(GL_QUADS); glTexCoord2f(0, 0); glVertex3f(-s, -s, s); glTexCoord2f(0, t); glVertex3f(-s, s, s); glTexCoord2f(t, t); glVertex3f(s, s, s); glTexCoord2f(t, 0); glVertex3f(s, -s, s); glEnd(); // Render the right quad // glBindTexture(GL_TEXTURE_2D, _skybox[3]); glBegin(GL_QUADS); glTexCoord2f(0, 0); glVertex3f(-s, -s, -s); glTexCoord2f(0, t); glVertex3f(-s, s, -s); glTexCoord2f(t, t); glVertex3f(-s, s, s); glTexCoord2f(t, 0); glVertex3f(-s, -s, s); glEnd(); // Render the top quad //glBindTexture(GL_TEXTURE_2D, _skybox[4]); glBegin(GL_QUADS); glTexCoord2f(0, t); glVertex3f(-s, s, -s); glTexCoord2f(t, t); glVertex3f(s, s, -s); glTexCoord2f(t, 0); glVertex3f(s, s, s); glTexCoord2f(0, 0); glVertex3f(-s, s, s); glEnd(); // Render the bottom quad //glBindTexture(GL_TEXTURE_2D, _skybox[5]); glBegin(GL_QUADS); glTexCoord2f(0, 0); glVertex3f(-s, -s, -s); glTexCoord2f(0, t); glVertex3f(-s, -s, s); glTexCoord2f(t, t); glVertex3f(s, -s, s); glTexCoord2f(t, 0); glVertex3f(s, -s, -s); glEnd(); // Restore enable bits and matrix glPopAttrib(); glPopMatrix(); } class Application { public: void initialize(int argc, char ** argv); void update(); void shutdown(); bool isRunning(); private: bool running; double last_time, last_bomb; //TODO: use bomb schedule; int last_x, last_y; double phi, theta; double camX, camY, camZ; Schedule accelerate_schudule; Schedule game_update_schudule; game_t game; int server; int width, height; //TrueTyeFont font; oglf_font_t font; void prepareFrame(double rx, double ry, double rz); void accelerate(double x, double y, double z); void drop_bomb(double rx, double ry, double rz, double ttl); void loadConsoleFont(); }; void Application::accelerate(double x, double y, double z) { if (game.local_player == 0) return; player_accelerate_message_t msg; msg.msg_id = MESSAGE_PLAYER_ACCELERATE; msg.player_id = game.local_player->id; msg.x = x; msg.y = y; msg.z = z; send_message((uint8_t*) &msg, sizeof(msg), &game); } void Application::drop_bomb(double rx, double ry, double rz, double ttl) { bomb_drop_meesage_t msg; msg.msg_id = MESSAGE_BOMB_DROP; msg.x = game.local_player->x + rx * 20; msg.y = game.local_player->y + ry * 20; msg.z = game.local_player->z + rz * 20; msg.vx = game.local_player->vx + rx * 100; msg.vy = game.local_player->vy + ry * 100; msg.vz = game.local_player->vz + rz * 100; msg.ttl = ttl; send_message((uint8_t*) &msg, sizeof(msg), &game); } void Application::loadConsoleFont() { GLuint font_id = 0; glGenTextures(1, &font_id); glBindTexture(GL_TEXTURE_2D, font_id); // Set texture parameters glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); // Upload texture from file to texture memory glfwLoadTexture2D("data/fonts/console.tga", 0); oglf_load(&font, "data/fonts/console.fnt", font_id); } void Application::prepareFrame(double rx, double ry, double rz) { // Get window size (may be different than the requested size) glfwGetWindowSize(&width, &height); height = height > 0 ? height : 1; // Set viewport glViewport(0, 0, width, height); // Clear color buffer glClearColor(0.0f, 0.0f, 0.0f, 0.0f); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // Select and setup the projection matrix glMatrixMode( GL_PROJECTION); glLoadIdentity(); gluPerspective(60.0f, (GLfloat) width / (GLfloat) height, 1.0f, 10000.0f); // Select and setup the modelview matrix glMatrixMode( GL_MODELVIEW); glLoadIdentity(); gluLookAt(camX, camY, camZ, camX + rx * 10.0f, camY + ry * 10.0f, camZ + rz * 10.0f, 0.0f, 1.0f, 0.0f); } void Application::initialize(int argc, char ** argv) { server = 0; double time, last_player_update; std::string arg1; if (argc > 1) { arg1 = argv[1]; if (arg1 == "server") { server = 1; } else { server = 0; } } else { server = 0; arg1 = "forge.camijo.de"; } // Initialise GLFW if (!glfwInit()) { fprintf(stderr, "Failed to initialize GLFW\n"); exit(EXIT_FAILURE); } game_setup(&game, server, explosion_callback); setup_opengl(); setup_explosion(); quadratic = gluNewQuadric(); gluQuadricNormals(quadratic, GLU_SMOOTH); gluQuadricTexture(quadratic, GL_TRUE); if (server) { setup_network(NULL); team_t *team = game_team(&game, 0); game.local_player = game_spawn_player(&game, team); } else { setup_network(arg1.c_str()); } size_t i; running = GL_TRUE; last_time = PerformanceTimer::get(); last_player_update = last_time; last_bomb = last_time - 5.; glfwGetMousePos(&last_x, &last_y); accelerate_schudule.setExact(true); accelerate_schudule.setInterval(0.05); game_update_schudule.setExact(true); game_update_schudule.setInterval(0.05); loadConsoleFont(); } void Application::update() { // Get time and mouse position double time = PerformanceTimer::get(); double dt = time - last_time; int x, y; glfwGetMousePos(&x, &y); if (glfwGetMouseButton(GLFW_MOUSE_BUTTON_2) == GLFW_PRESS) { phi += (x - last_x) * 0.01; theta += (y - last_y) * -0.01; if (theta > 1.5) theta = 1.5; if (theta < -1.5) theta = -1.5; } last_x = x; last_y = y; double rx = cos(phi) * cos(theta); double ry = sin(theta); double rz = sin(phi) * cos(theta); service_network(&game); game_update(&game, dt); if (server && game_update_schudule.next(time)) { send_game_updates(&game); } if (accelerate_schudule.next(time)) { double t = accelerate_schudule.getInterval(); double v = 50.0 * t; if (glfwGetKey('W')) { accelerate(rx * v, ry * v, rz * v); } else if (glfwGetKey('S')) { accelerate(rx * -v, ry * -v, rz * -v); } if (glfwGetKey('A')) { accelerate(rz * v, 0, -rx * v); } else if (glfwGetKey('D')) { accelerate(-rz * v, 0, rx * v); } if (glfwGetKey(GLFW_KEY_SPACE)) { accelerate(game.local_player->vx * -0.1, game.local_player->vy * -0.1, game.local_player->vz * -0.1); } } if (glfwGetKey(GLFW_KEY_LCTRL)) { if (time - last_bomb > 1.0) { last_bomb = time; drop_bomb(rx, ry, rz, 5.0); } } if (game.local_player) { camX = game.local_player->x; camY = game.local_player->y; camZ = game.local_player->z; } else { camX = 1000.0; camY = 1000.0; camZ = 1000.0; } prepareFrame(rx, ry, rz); setup_light(); glEnable( GL_LIGHT0); glEnable( GL_LIGHTING); glEnable( GL_CULL_FACE); glDisable( GL_TEXTURE_2D); for (size_t i = 0; i < GAME_TEAM_COUNT; i++) draw_team(&game.team[i]); for (size_t i = 0; i < GAME_PLAYER_COUNT; i++) draw_player(&game.player[i]); for (size_t i = 0; i < GAME_BOMB_COUNT; i++) draw_bomb(&game.bomb[i]); for (size_t i = 0; i < GAME_POINT_COUNT; i++) draw_point(&game.point[i]); draw_box(); glDisable(GL_LIGHT0); glDisable(GL_LIGHTING); glDisable(GL_CULL_FACE); explosion.update(dt * 1000.0, camX, camY, camZ); explosion.render(); oglf_begin(&font, width, height); size_t fy = 1; if (game.local_player) { std::stringstream sstr; sstr << "Points: " << game.local_player->points; oglf_print(&font, 10, 25 * fy++, sstr.str().c_str()); } for (size_t i = 0; i < GAME_TEAM_COUNT; i++) { std::stringstream sstr; if (game.local_player && &game.team[i] == game.local_player->team) { sstr << "Team " << i << " (yours) : " << game.team[i].points; } else { sstr << "Team " << i << " (other) : " << game.team[i].points; } oglf_print(&font, 10, 25 * fy++, sstr.str().c_str()); } { std::stringstream sstr; sstr << "FPS: " << (int) (1 / dt) << " Time: " << round(dt * 10000.0) / 10.0; oglf_print(&font, 10, 25 * fy++, sstr.str().c_str()); } oglf_end(); // Swap buffers glfwSwapBuffers(); // Check if the ESC key was pressed or the window was closed running = !glfwGetKey(GLFW_KEY_ESC) && glfwGetWindowParam(GLFW_OPENED); last_time = time; } void Application::shutdown() { gluDeleteQuadric(quadratic); oglf_destroy(&font); shutdown_network(); // Close OpenGL window and terminate GLFW glfwTerminate(); } bool Application::isRunning() { return running; } int main(int argc, char ** argv) { Application app; app.initialize(argc, argv); while (app.isRunning()) app.update(); app.shutdown(); return 0; }