SyndicatQuebecoisdelaConstr.../SQCSim2021/engine.cpp
2021-11-19 08:35:19 -05:00

399 lines
12 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include "engine.h"
#include <algorithm>
#include <cmath>
#include "transformation.h"
#include "player.h"
Engine::Engine() { }
Engine::~Engine() { }
void Engine::Init()
{
GLenum glewErr = glewInit();
if (glewErr != GLEW_OK) {
std::cerr << " ERREUR GLEW : " << glewGetErrorString(glewErr) << std::endl;
abort();
}
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
glEnable(GL_TEXTURE_2D);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(45.0f, (float)Width() / (float)Height(), 0.0001f, 1000.0f);
glEnable(GL_DEPTH_TEST);
glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);
glShadeModel(GL_SMOOTH);
glEnable(GL_LIGHTING);
glEnable(GL_LINE_SMOOTH);
glEnable(GL_CULL_FACE);
// Light
GLfloat light0Pos[4] = { 0.0f, CHUNK_SIZE_Y, 0.0f, 1.0f };
GLfloat light0Amb[4] = { 0.2f, 0.2f, 0.2f, 1.f };
GLfloat light0Diff[4] = { 1.f, 1.f, 1.f, 1.f };
GLfloat light0Spec[4] = { 0.2f, 0.2f, 0.2f, 1.0f };
glEnable(GL_LIGHT0);
glLightfv(GL_LIGHT0, GL_POSITION, light0Pos);
glLightfv(GL_LIGHT0, GL_AMBIENT, light0Amb);
glLightfv(GL_LIGHT0, GL_DIFFUSE, light0Diff);
glLightfv(GL_LIGHT0, GL_SPECULAR, light0Spec);
// Objet de skybox avec sa propre texture et son propre shader!
m_skybox.Init(0.00013f);
// Objet de musique!
m_audio.ToggleMusicState();
// Init Chunks
for (int chx = 0; chx < VIEW_DISTANCE; ++chx) // Un beau gros monde de VIEW_DISTANCE Chunks par VIEW_DISTANCE Chunks.
for (int chy = 0; chy < VIEW_DISTANCE; ++chy)
m_world.GetChunks().Set(chx, chy, new Chunk(chx, chy));
// Génération Chunks.
for (int chx = 0; chx < VIEW_DISTANCE; ++chx)
for (int chy = 0; chy < VIEW_DISTANCE; ++chy) {
for (int x = 0; x < CHUNK_SIZE_X; ++x)
for (int z = 0; z < CHUNK_SIZE_Z; ++z)
for (int y = 0; y < 32; ++y)
m_world.GetChunks().Get(chx, chy)->SetBlock(x, y, z, ((chx + chy) % (BTYPE_LAST - 1)) + 1);
m_world.GetChunks().Get(chx, chy)->SetBlock(5, 32, 15, BTYPE_GRASS);
m_world.GetChunks().Get(chx, chy)->SetBlock(5, 33, 15, BTYPE_GRASS);
m_world.GetChunks().Get(chx, chy)->SetBlock(5, 34, 15, BTYPE_GRASS);
m_world.GetChunks().Get(chx, chy)->SetBlock(6, 34, 15, BTYPE_GRASS);
m_world.GetChunks().Get(chx, chy)->SetBlock(7, 34, 15, BTYPE_GRASS);
m_world.GetChunks().Get(chx, chy)->SetBlock(7, 33, 15, BTYPE_GRASS);
m_world.GetChunks().Get(chx, chy)->SetBlock(7, 32, 15, BTYPE_GRASS);
m_world.GetChunks().Get(chx, chy)->SetBlock(8, 32, 3, BTYPE_GRASS);
m_world.GetChunks().Get(chx, chy)->SetBlock(8, 33, 4, BTYPE_GRASS);
m_world.GetChunks().Get(chx, chy)->SetBlock(8, 34, 5, BTYPE_GRASS);
m_world.GetChunks().Get(chx, chy)->SetBlock(8, 35, 6, BTYPE_GRASS);
m_world.GetChunks().Get(chx, chy)->SetBlock(11, 32, 5, BTYPE_GRASS);
m_world.GetChunks().Get(chx, chy)->SetBlock(11, 33, 5, BTYPE_GRASS);
m_world.GetChunks().Get(chx, chy)->SetBlock(11, 34, 5, BTYPE_GRASS);
m_world.GetChunks().Get(chx, chy)->SetBlock(11, 35, 5, BTYPE_GRASS);
m_world.GetChunks().Get(chx, chy)->SetBlock(12, 32, 5, BTYPE_GRASS);
m_world.GetChunks().Get(chx, chy)->SetBlock(12, 33, 5, BTYPE_GRASS);
m_world.GetChunks().Get(chx, chy)->SetBlock(12, 34, 5, BTYPE_GRASS);
m_world.GetChunks().Get(chx, chy)->SetBlock(12, 35, 5, BTYPE_GRASS);
m_world.GetChunks().Get(chx, chy)->SetBlock(13, 32, 5, BTYPE_GRASS);
m_world.GetChunks().Get(chx, chy)->SetBlock(13, 33, 5, BTYPE_GRASS);
m_world.GetChunks().Get(chx, chy)->SetBlock(13, 34, 5, BTYPE_GRASS);
m_world.GetChunks().Get(chx, chy)->SetBlock(13, 35, 5, BTYPE_GRASS);
m_world.GetChunks().Get(chx, chy)->SetBlock(14, 32, 5, BTYPE_GRASS);
m_world.GetChunks().Get(chx, chy)->SetBlock(14, 33, 5, BTYPE_GRASS);
m_world.GetChunks().Get(chx, chy)->SetBlock(14, 34, 5, BTYPE_GRASS);
m_world.GetChunks().Get(chx, chy)->SetBlock(14, 35, 5, BTYPE_GRASS);
}
// Gestion de souris.
CenterMouse();
HideCursor();
}
void Engine::DeInit() { }
void Engine::LoadResource() {
LoadTexture(m_textureFloor, TEXTURE_PATH "grass.png");
LoadTexture(m_skybox.GetTexture(), TEXTURE_PATH "skybox.png");
LoadTexture(m_textureCrosshair, TEXTURE_PATH "cross.bmp");
LoadTexture(m_textureFont, TEXTURE_PATH "font.bmp");
TextureAtlas::TextureIndex texDirtIndex = m_textureAtlas.AddTexture(TEXTURE_PATH "metal3.png");
TextureAtlas::TextureIndex texIceIndex = m_textureAtlas.AddTexture(TEXTURE_PATH "dirt.png");
TextureAtlas::TextureIndex texGrassIndex = m_textureAtlas.AddTexture(TEXTURE_PATH "grass.png");
TextureAtlas::TextureIndex texMetalIndex = m_textureAtlas.AddTexture(TEXTURE_PATH "metal.png");
if (!m_textureAtlas.Generate(512, false)) {
std::cout << " Unable to generate texture atlas ..." << std::endl;
abort();
}
float u, v, s;
m_textureAtlas.TextureIndexToCoord(texDirtIndex, u, v, s, s);
m_blockinfo[BTYPE_DIRT] = new BlockInfo(BTYPE_DIRT, "Dirt", u, v, s, 1);
m_textureAtlas.TextureIndexToCoord(texGrassIndex, u, v, s, s);
m_blockinfo[BTYPE_GRASS] = new BlockInfo(BTYPE_GRASS, "Grass", u, v, s, 1);
m_textureAtlas.TextureIndexToCoord(texMetalIndex, u, v, s, s);
m_blockinfo[BTYPE_METAL] = new BlockInfo(BTYPE_METAL, "Metal", u, v, s, 1);
m_textureAtlas.TextureIndexToCoord(texIceIndex, u, v, s, s);
m_blockinfo[BTYPE_ICE] = new BlockInfo(BTYPE_ICE, "Ice", u, v, s, 1);
std::cout << " Loading and compiling shaders ..." << std::endl;
if (!m_shader01.Load(SHADER_PATH "shader01.vert", SHADER_PATH "shader01.frag", true)) {
std::cout << " Failed to load shader " << std::endl;
exit(1);
}
if (!m_skybox.GetShader().Load(SHADER_PATH "skybox.vert", SHADER_PATH "skybox.frag", true)) {
std::cout << " Failed to load shader " << std::endl;
exit(1);
}
}
void Engine::UnloadResource() {}
void Engine::DrawHud(float elapsedTime) {
// Setter le blend function , tout ce qui sera noir sera transparent
glDisable(GL_LIGHTING);
glColor4f(1.f, 1.f, 1.f, 1.f);
glBlendFunc(GL_SRC_ALPHA, GL_ONE);
glEnable(GL_BLEND);
glDisable(GL_DEPTH_TEST);
glMatrixMode(GL_PROJECTION);
glPushMatrix();
glLoadIdentity();
glOrtho(0, Width(), 0, Height(), -1, 1);
glMatrixMode(GL_MODELVIEW);
glPushMatrix();
// Bind de la texture pour le font
m_textureFont.Bind();
std::ostringstream ss;
ss << " Fps : " << GetFps(elapsedTime);
PrintText(10, Height() - 25, ss.str());
ss.str("");
ss << " Velocity : " << m_player.GetVelocity(); // IMPORTANT : on utilise l operateur << pour afficher la position
PrintText(10, 10, ss.str());
ss.str("");
ss << " Direction : " << m_player.GetDirection();
PrintText(10, 20, ss.str());
ss.str("");
ss << " Position : " << m_player.GetPosition();
PrintText(10, 30, ss.str());
ss.str("");
ss << " CamPos : " << m_player.GetPOV();
PrintText(10, 40, ss.str());
// Affichage du crosshair
m_textureCrosshair.Bind();
static const int crossSize = 32;
glLoadIdentity();
glTranslated(Width() / 2 - crossSize / 2, Height() / 2 - crossSize / 2, 0);
glBegin(GL_QUADS);
glTexCoord2f(0, 0);
glVertex2i(0, 0);
glTexCoord2f(1, 0);
glVertex2i(crossSize, 0);
glTexCoord2f(1, 1);
glVertex2i(crossSize, crossSize);
glTexCoord2f(0, 1);
glVertex2i(0, crossSize);
glEnd();
glEnable(GL_LIGHTING);
glDisable(GL_BLEND);
glEnable(GL_DEPTH_TEST);
glMatrixMode(GL_PROJECTION);
glPopMatrix();
glMatrixMode(GL_MODELVIEW);
glPopMatrix();
}
void Engine::PrintText(unsigned int x, unsigned int y, const std::string& t) {
glLoadIdentity();
glTranslated(x, y, 0);
for (unsigned int i = 0; i < t.length(); ++i) {
float left = (float)((t[i] - 32) % 16) / 16.f;
float top = (float)((t[i] - 32) / 16) / 16.f;
top += .5f;
glBegin(GL_QUADS);
glTexCoord2f(left, 1.f - top - .0625f);
glVertex2f(0, 0);
glTexCoord2f(left + .0625f, 1.f - top - .0625f);
glVertex2f(12, 0);
glTexCoord2f(left + .0625f, 1.f - top);
glVertex2f(12, 12);
glTexCoord2f(left, 1.f - top);
glVertex2f(0, 12);
glEnd();
glTranslated(8, 0, 0);
}
}
int Engine::GetFps(float elapsedTime) const { return 1 / elapsedTime; }
void Engine::Render(float elapsedTime) {
static float gameTime = elapsedTime;
if (elapsedTime > 0.1f) return;
gameTime += elapsedTime;
Transformation all;
Transformation skybox;
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
// Transformations initiales
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
m_player.ApplyPhysics(m_player.GetInput(m_keyW, m_keyS, m_keyA, m_keyD, m_keySpace, m_keylshift, elapsedTime), m_world, elapsedTime);
m_audio.Update3DAudio(m_player.GetPOV(), m_player.GetDirection(), m_player.GetVelocity()); // Ajustement du positionnement 3D avec les coordonnées du joueur et
// son vecteur de vélocité (pour l'effet Doppler)
m_player.ApplyTransformation(all);
m_player.ApplyTransformation(skybox, false); // Version d'ApplyTransformation qui ne tient compte que de la rotation
// (donc l'objet ne bouge pas relativement au joueur, ce qui est pratique pour une skybox!).
glDisable(GL_LIGHT0);
m_skybox.Render(skybox);
// Chunks
all.Use();
glEnable(GL_LIGHT0);
m_shader01.Use();
m_textureAtlas.Bind();
for (int chx = 0; chx < VIEW_DISTANCE; chx++)
for (int chy = 0; chy < VIEW_DISTANCE; chy++) {
all.ApplyTranslation(chx * CHUNK_SIZE_X, 0, chy * CHUNK_SIZE_Z);
all.Use();
if (m_world.GetChunks().Get(chx, chy)->IsDirty())
m_world.GetChunks().Get(chx, chy)->Update(m_blockinfo, &m_world);
m_world.GetChunks().Get(chx, chy)->Render();
all.ApplyTranslation(-chx * CHUNK_SIZE_X, 0, -chy * CHUNK_SIZE_Z);
}
m_shader01.Disable();
if (m_wireframe)
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
DrawHud(elapsedTime);
if (m_wireframe)
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
if (m_player.GetPosition().y < -20.f) m_player = Player(Vector3f(VIEW_DISTANCE * CHUNK_SIZE_X / 2, CHUNK_SIZE_Y / 2, VIEW_DISTANCE * CHUNK_SIZE_Z / 2)); // Respawn si le bonho- joueur tombe en bas du monde.
}
void Engine::KeyPressEvent(unsigned char key)
{
switch (key) {
case 36: // ESC
Stop();
break;
case 94: // F10
SetFullscreen(!IsFullscreen());
break;
case 22: // W
if (!m_keyW) {
std::cout << "W " << std::endl;
m_keyW = true;
}
break;
case 0: // A
if (!m_keyA) {
std::cout << "A " << std::endl;
m_keyA = true;
}
break;
case 18: // S
if (!m_keyS) {
std::cout << "S " << std::endl;
m_keyS = true;
}
break;
case 3: // D
if (!m_keyD) {
std::cout << "D " << std::endl;
m_keyD = true;
}
break;
case 38: // Left Shift
if (!m_keylshift) {
std::cout << "Dash!" << std::endl;
m_keylshift = true;
}
break;
case 57: // Space
if (!m_keySpace) {
std::cout << "Jump! " << std::endl;
m_keySpace = true;
}
break;
case 24: // Y - Ignorer
case 255: // Fn - Ignorer
case 12: // M - Ignorer
break;
default:
std::cout << "Unhandled key: " << (int)key << std::endl;
}
}
void Engine::KeyReleaseEvent(unsigned char key)
{
switch (key) {
case 12:
m_audio.ToggleMusicState();
break;
case 24: // Y
m_wireframe = !m_wireframe;
if (m_wireframe)
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
else
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
break;
case 22: // W
std::cout << "rW " << std::endl;
m_keyW = false;
break;
case 0: // A
std::cout << "rA " << std::endl;
m_keyA = false;
break;
case 18: // S
std::cout << "rS " << std::endl;
m_keyS = false;
break;
case 3: // D
std::cout << "rD " << std::endl;
m_keyD = false;
break;
case 38: // Left Shift
std::cout << "rLS " << std::endl;
m_keylshift = false;
case 57: // Espace
std::cout << "rSpace " << std::endl;
m_keySpace = false;
break;
}
}
void Engine::MouseMoveEvent(int x, int y)
{
m_player.TurnLeftRight(x - (Width() / 2));
m_player.TurnTopBottom(y - (Height() / 2));
// Centrer la souris seulement si elle n'est pas déjà centrée
// Il est nécessaire de faire la vérification pour éviter de tomber
// dans une boucle infinie où l'appel à CenterMouse génère un
// MouseMoveEvent, qui rapelle CenterMouse qui rapelle un autre
// MouseMoveEvent, etc
if (x == (Width() / 2) && y == (Height() / 2))
return;
CenterMouse();
}
void Engine::MousePressEvent(const MOUSE_BUTTON& button, int x, int y)
{
}
void Engine::MouseReleaseEvent(const MOUSE_BUTTON& button, int x, int y)
{
}
bool Engine::LoadTexture(Texture& texture, const std::string& filename, bool stopOnError)
{
texture.Load(filename);
if (!texture.IsValid())
{
std::cerr << "Unable to load texture (" << filename << ")" << std::endl;
if (stopOnError)
Stop();
return false;
}
return true;
}