/* * Client.cpp * * Created on: 14.01.2011 * Author: gmueller */ #include "Client.h" #include "Network.h" #include "Explosion.h" #include "Time.h" #include "btBulletDynamicsCommon.h" #include #include #include #include #include #include GLUquadricObj *quadratic; Explosion explosion; 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"); // 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 *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(); } GLuint wallTex = 0; void Client::drawPlayer(player_t *player) { if (player->status == 0) return; glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, player->team->color); glMatrixMode(GL_MODELVIEW); glPushMatrix(); glMultMatrixf(player->m); glEnableClientState(GL_VERTEX_ARRAY); glEnableClientState(GL_TEXTURE_COORD_ARRAY); glEnableClientState(GL_NORMAL_ARRAY); glVertexPointer(3, GL_FLOAT, game.shipMesh->vertex_size, game.shipMesh->vertices); glTexCoordPointer(2, GL_FLOAT, game.shipMesh->vertex_size, game.shipMesh->vertices + 3); glNormalPointer(GL_FLOAT, game.shipMesh->vertex_size, game.shipMesh->vertices + 5); for (size_t i = 0; i < game.shipMesh->object_count; i++) { glDrawElements(GL_TRIANGLES, game.shipMesh->objects[i].face_count * 3, GL_UNSIGNED_SHORT, &game.shipMesh->faces[game.shipMesh->objects[i].face_index]); } glDisableClientState(GL_VERTEX_ARRAY); glDisableClientState(GL_TEXTURE_COORD_ARRAY); 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, 0.5f, 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 Client::drawLevel() { 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); glColor4f(1, 1, 1, 1); glMatrixMode(GL_MODELVIEW); glPushMatrix(); #if 0 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. // 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(); #else glEnableClientState(GL_VERTEX_ARRAY); glEnableClientState(GL_TEXTURE_COORD_ARRAY); glEnableClientState(GL_NORMAL_ARRAY); glVertexPointer(3, GL_FLOAT, game.levelMesh->vertex_size, game.levelMesh->vertices); glTexCoordPointer(2, GL_FLOAT, game.levelMesh->vertex_size, game.levelMesh->vertices + 3); glNormalPointer(GL_FLOAT, game.levelMesh->vertex_size, game.levelMesh->vertices + 5); for (size_t i = 0; i < game.levelMesh->object_count; i++) { glDrawElements(GL_TRIANGLES, game.levelMesh->objects[i].face_count * 3, GL_UNSIGNED_SHORT, &game.levelMesh->faces[game.levelMesh->objects[i].face_index]); } glDisableClientState(GL_VERTEX_ARRAY); glDisableClientState(GL_TEXTURE_COORD_ARRAY); #endif // Restore enable bits and matrix glPopAttrib(); glPopMatrix(); } void Client::accelerate(double x, double y, double z) { if (game.local_player == 0) return; player_accelerate_message_t msg; msg.player_id = game.local_player->id; msg.x = x; msg.y = y; msg.z = z; YAML::Emitter m; m << msg; network.send(m); } void Client::drop_bomb(double rx, double ry, double rz, double ttl) { bomb_drop_meesage_t msg; btVector3 p = game.local_player->body->getWorldTransform().getOrigin(); btVector3 v = game.local_player->body->getLinearVelocity(); msg.x = p.x() + rx * 1; msg.y = p.y() + ry * 1; msg.z = p.z() + rz * 1; msg.vx = v.x() + rx * 500; msg.vy = v.y() + ry * 500; msg.vz = v.z() + rz * 500; msg.ttl = ttl; YAML::Emitter m; m << msg; network.send(m); } void Client::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 Client::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 Client::initialize(Arguments &arg) { Application::initialize(arg); // Initialise GLFW if (!glfwInit()) { throw("Failed to initialize GLFW"); } setup_opengl(); setup_explosion(); quadratic = gluNewQuadric(); gluQuadricNormals(quadratic, GLU_SMOOTH); gluQuadricTexture(quadratic, GL_TRUE); if (isMaster()) { Team *team = game.getTeam(0); game.local_player = game.spawnPlayer(team); std::cout << "[Game] local player " << game.local_player->id << std::endl; } size_t i; last_bomb = time - 5.; glfwGetMousePos(&last_x, &last_y); accelerate_schudule.setExact(true); accelerate_schudule.setInterval(0.05); theta = 0.0; phi = 0.0; loadConsoleFont(); // setup signals game.ExplosionSignal.connect(this, &Client::onExplosion); } void Client::update() { Application::update(); 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); 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 0 if (glfwGetKey(GLFW_KEY_SPACE)) { accelerate(game.local_player->vx * -0.1, game.local_player->vy * -0.1, game.local_player->vz * -0.1); } #endif } 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) { btVector3 p = game.local_player->body->getWorldTransform().getOrigin(); camX = p.x(); camY = p.y(); camZ = p.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.teams.size(); i++) // draw_team(&game.teams[i]); for (size_t i = 0; i < GAME_PLAYER_COUNT; i++) drawPlayer(&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]); drawLevel(); explosion.update(dt * 1000.0, camX, camY, camZ); explosion.render(); glDisable(GL_LIGHT0); glDisable(GL_LIGHTING); glDisable(GL_CULL_FACE); 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.teams.size(); i++) { std::stringstream sstr; if (game.local_player && &game.teams[i] == game.local_player->team) { sstr << "Team " << i << " (yours) : " << game.teams[i].points; } else { sstr << "Team " << i << " (other) : " << game.teams[i].points; } oglf_print(&font, 10, 25 * fy++, sstr.str().c_str()); } { std::stringstream sstr; sstr << "FPS: " << (int) (1 / dt) << " Time: " << floor(dt * 10000.0 + 0.5) / 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 if (glfwGetKey(GLFW_KEY_ESC)) stop(); if (glfwGetWindowParam(GLFW_OPENED) != GL_TRUE) stop(); } void Client::shutdown() { Application::shutdown(); gluDeleteQuadric(quadratic); oglf_destroy(&font); glfwTerminate(); } void Client::onExplosion(double x, double y, double z) { explosion.add(x, y, z); }