diff --git a/src/gamelogic.cpp b/src/gamelogic.cpp index 31d1e8a..66284fc 100644 --- a/src/gamelogic.cpp +++ b/src/gamelogic.cpp @@ -1,4 +1,4 @@ -#include "gamelogic.h" +#include "gamelogic.hpp" #include "sceneGraph.hpp" #include #include @@ -11,12 +11,7 @@ #include #include #include -#include -#include -#include -#include #include -#include #include using glm::vec3; @@ -24,62 +19,16 @@ using glm::vec4; using glm::mat4; typedef unsigned int uint; -uint currentKeyFrame = 0; -uint previousKeyFrame = 0; - -SceneNode* rootNode; -SceneNode* plainNode; -SceneNode* carNode; -SceneNode* treeNode; -SceneNode* boxNode; -SceneNode* sphereNode; -SceneNode* hudNode; -SceneNode* textNode; - -const uint N_LIGHTS = 3; -SceneNode* lightNode[N_LIGHTS]; - -// These are heap allocated, because they should not be initialised at the start of the program sf::Sound* sound; sf::SoundBuffer* buffer; -Gloom::Shader* default_shader; -Gloom::Shader* test_shader; -Gloom::Shader* plain_shader; -Gloom::Shader* post_shader; - -vec3 cameraPosition = vec3(0, 0, 400); -vec3 cameraLookAt = vec3(500, 500, 0); -vec3 cameraUpward = vec3(0, 0, 1); - -CommandLineOptions options; - -bool hasStarted = false; -bool hasLost = false; -bool jumpedToNextFrame = false; - -// Modify if you want the music to start further on in the track. Measured in seconds. -const float debug_startTime = 45; -double totalElapsedTime = debug_startTime; - -// textures -PNGImage t_charmap = loadPNGFile("../res/textures/charmap.png"); -PNGImage t_cobble_diff = loadPNGFile("../res/textures/cobble_diff.png"); -PNGImage t_cobble_normal = loadPNGFile("../res/textures/cobble_normal.png"); -PNGImage t_plain_diff = loadPNGFile("../res/textures/plain_diff.png"); -PNGImage t_plain_normal = loadPNGFile("../res/textures/plain_normal.png", true); -PNGImage t_reflection = loadPNGFile("../res/textures/reflection_field.png"); -PNGImage t_reflection2 = loadPNGFile("../res/textures/reflection_blurry.png"); -PNGImage t_perlin = makePerlinNoisePNG(256, 256, 0.05/16); - - void mouseCallback(GLFWwindow* window, double x, double y) { int windowWidth, windowHeight; glfwGetWindowSize(window, &windowWidth, &windowHeight); glViewport(0, 0, windowWidth, windowHeight); - - float mousePositionX = x / double(windowHeight); // like the hudNode space - float mousePositionY = y / double(windowHeight); + + mouse_position_cb(x, y, windowWidth, windowHeight); + /* if(padPositionX > 1) { padPositionX = 1; @@ -98,178 +47,22 @@ void mouseCallback(GLFWwindow* window, double x, double y) { */ } -void initGame(GLFWwindow* window, CommandLineOptions gameOptions) { +void initRenderer(GLFWwindow* window, CommandLineOptions options) { buffer = new sf::SoundBuffer(); if (!buffer->loadFromFile("../res/Hall of the Mountain King.ogg")) { return; } - options = gameOptions; - glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_HIDDEN); glfwSetCursorPosCallback(window, mouseCallback); - - // load shaders - default_shader = new Gloom::Shader(); - default_shader->makeBasicShader("../res/shaders/simple.vert", "../res/shaders/simple.frag"); - - Mesh box = generateBox(50, 50, 50); - Mesh sphere = generateSphere(10, 100, 100); - Mesh plain = generateSegmentedPlane(1000, 1000, 100, 100, 3); - Mesh hello_world = generateTextGeometryBuffer("Skjer'a bagera?", 1.3, 2); - t_perlin.repeat_mirrored = true; - - rootNode = createSceneNode(); - hudNode = createSceneNode(); - - // create and add lights to graph - for (uint i = 0; ilightID = i; - rootNode->children.push_back(lightNode[i]); - } - - - //treeNode = loadModelScene("../res/models/fur_tree/scene.gltf"); - //treeNode->position = {300, 800, 10}; - //rootNode->children.push_back(treeNode); - - carNode = loadModelScene("../res/models/beetle/scene.gltf", { - { 0, Material().diffuse({0.0, 0.0, 1.0}).diffuse_only().reflection_mapped(&t_reflection, 0.15)},// Blue_Metal - { 1, Material().diffuse(vec3(0.85)).emissive(vec3(0.1)).reflection_mapped(&t_reflection, -1.0)},// Metal (decals) - //{ 2, Material().diffuse({1.0, 1.0, 1.0})},// Front_Light_Glass - // { 3, Material().diffuse({0.2, 0.2, 0.2})},// Black_Rubber - { 4, Material().no_colors().reflection_mapped(&t_reflection, 1.0)},// Mirror - //{ 5, Material().diffuse({1.0, 1.0, 1.0})},// Black_Metal - //{ 6, Material().diffuse({1.0, 1.0, 1.0})},// Plastic -// { 7, Material().diffuse(vec3(0.2)).emissive(vec3(0.25)).specular(vec3(1.0), 70).reflection_mapped(&t_reflection, -0.8)},// Window_Glass - { 7, Material().diffuse(vec3(0.2)).emissive(vec3(0.25)).specular(vec3(1.0), 70).reflection_mapped(&t_reflection, -0.8)},// Window_Glass - //{ 8, Material().diffuse({1.0, 1.0, 1.0})},// Material - { 9, Material().diffuse(vec3(1.0)).emissive(vec3(0.2)).specular(vec3(0.4), 70).reflection_mapped(&t_reflection, -1.0)},// Glossy_metal - //{10, Material().diffuse({1.0, 1.0, 1.0})},// Rogh_Metal -// {11, Material().no_colors().reflection_mapped(&t_reflection, 1.0)},// License_Plate_Metal - {11, Material().no_colors().reflection_mapped(&t_reflection, 1.0)},// License_Plate_Metal - //{12, Material().diffuse({1.0, 1.0, 1.0})},// License_Plate_Frame - //{13, Material().diffuse({1.0, 1.0, 1.0})},// - }); - //carNode->setMaterial(Material().reflection_mapped(&t_reflection, 0.0).no_colors().no_texture_reset(), true); - carNode->position = {500, 500, 100}; - carNode->scale *= 100; - rootNode->children.push_back(carNode); - - //create the scene: - plainNode = createSceneNode(); - plainNode->setTexture(&t_plain_diff, &t_plain_normal, &t_perlin); - plainNode->setMesh(&plain); - plainNode->position = {0, 0, 0}; - plainNode->shininess = 20; - plainNode->displacementCoefficient = 40; - rootNode->children.push_back(plainNode); - - /* - boxNode = createSceneNode(); - boxNode->setTexture(&t_cobble_diff, &t_cobble_normal); - boxNode->setMesh(&box); - boxNode->position = {500, 500, 40}; - boxNode->referencePoint = {25, 25, 25}; - boxNode->scale *= 2; - boxNode->shininess = 20; - boxNode->displacementCoefficient = 40; - rootNode->children.push_back(boxNode); - */ - - sphereNode = createSceneNode(); - //sphereNode->setTexture(&t_cobble_diff, &t_cobble_normal); - sphereNode->setMesh(&sphere); - sphereNode->position = {500, 500, 100}; - sphereNode->scale *= 15; - sphereNode->diffuse_color; - sphereNode->setMaterial(Material().reflection_mapped(&t_reflection, 0.5).no_colors().no_texture_reset(), true); - //rootNode->children.push_back(sphereNode); - - lightNode[0]->position = {-600, 1400, 800}; - lightNode[0]->attenuation = vec3(1.8, 0.0, 0.0); - - lightNode[1]->position = {500, 0, 80}; - lightNode[1]->referencePoint = {0, 500, 0}; - lightNode[1]->scale *= 0.8; - lightNode[1]->light_color = vec3(0.0); - lightNode[1]->attenuation = vec3(1.0, 0.0, 0.000005); - - lightNode[2]->position = {400, -200, 300}; - lightNode[2]->nodeType = SPOT_LIGHT; - lightNode[2]->attenuation = vec3(1, 0, 0); - lightNode[2]->spot_target = lightNode[1]; - - textNode = createSceneNode(); - textNode->setTexture(&t_charmap); - textNode->setMesh(&hello_world); - textNode->position = vec3(-1.0, -1.0, 0.0); - textNode->isIlluminated = false; - textNode->isInverted = true; - hudNode->children.push_back(textNode); + init_scene(options); + // init getTimeDeltaSeconds(); - - std::cout << "Ready. Click to start!" << std::endl; -} - -void stepScene(double timeDelta) { - static double timeAcc = 0; // shrug - timeAcc += timeDelta; - - plainNode->uvOffset.x += timeDelta*0.5; - plainNode->uvOffset.y -= timeDelta*0.5; - if (boxNode) boxNode->rotation.z += timeDelta; - lightNode[1]->rotation.z -= timeDelta; - //lightNode[1]->position.z = 80 + 40*glm::sin(5 * lightNode[1]->rotation.z); - //if(carNode) carNode->rotation.z += timeDelta; - - - - /* - if(!hasStarted) { - - if (glfwGetMouseButton(window, GLFW_MOUSE_BUTTON_1)) { - if (options.enableMusic) { - sound = new sf::Sound(); - sound->setBuffer(*buffer); - sf::Time startTime = sf::seconds(debug_startTime); - sound->setPlayingOffset(startTime); - sound->play(); - } - totalElapsedTime = debug_startTime; - hasStarted = true; - } - } else { - - // I really should calculate this using the std::chrono timestamp for this - // You definitely end up with a cumulative error when doing lots of small additions like this - // However, for a game that lasts only a few minutes this is fine. - totalElapsedTime += timeDelta; - - if(hasLost) { - //ballRadius += 200 * timeDelta; - //if(ballRadius > 999999) { - // ballRadius = 999999; - //} - } else { - for (uint i = currentKeyFrame; i < keyFrameTimeStamps.size(); i++) { - if (totalElapsedTime < keyFrameTimeStamps.at(i)) { - continue; - } - currentKeyFrame = i; - } - - jumpedToNextFrame = currentKeyFrame != previousKeyFrame; - previousKeyFrame = currentKeyFrame; - - } - } - */ } +// traverses and updates matricies void updateNodeTransformations(SceneNode* node, mat4 transformationThusFar, mat4 const& V, mat4 const& P) { mat4 transformationMatrix = glm::translate(mat4(1.0), node->position) @@ -290,14 +83,16 @@ void updateNodeTransformations(SceneNode* node, mat4 transformationThusFar, mat4 updateNodeTransformations(child, M, V, P); } +// step void updateFrame(GLFWwindow* window, int windowWidth, int windowHeight) { glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_DISABLED); double timeDelta = getTimeDeltaSeconds(); - - stepScene(timeDelta); - float aspect = float(windowWidth) / float(windowHeight); + // main action: + step_scene(timeDelta); + + // calculate camera mat4 projection = glm::perspective( glm::radians(45.0f), // fovy aspect, // aspect @@ -306,7 +101,8 @@ void updateFrame(GLFWwindow* window, int windowWidth, int windowHeight) { mat4 cameraTransform = glm::lookAt(cameraPosition, cameraLookAt, cameraUpward); - + + // update scene with camera updateNodeTransformations(rootNode, mat4(1.0), cameraTransform, projection); // We orthographic now, bitches! @@ -314,7 +110,7 @@ void updateFrame(GLFWwindow* window, int windowWidth, int windowHeight) { cameraTransform = mat4(1.0); projection = glm::ortho(-aspect, aspect, -1.0f, 1.0f); - //update hud + // update hud updateNodeTransformations(hudNode, mat4(1.0), cameraTransform, projection); // update spots @@ -328,7 +124,8 @@ void updateFrame(GLFWwindow* window, int windowWidth, int windowHeight) { } -void renderNode(SceneNode* node, Gloom::Shader* parent_shader = default_shader) { +// traverses and renders one and one node +void renderNode(SceneNode* node, Gloom::Shader* parent_shader) { struct Light { // lights as stored in the shader // coordinates in MV space vec3 position; // MV @@ -364,7 +161,7 @@ void renderNode(SceneNode* node, Gloom::Shader* parent_shader = default_shader) s->activate(); uint i = 0; for (Light l : lights) l.push_to_shader(s, i++); } - + switch(node->nodeType) { case GEOMETRY: if(node->vertexArrayObjectID != -1) { @@ -417,9 +214,11 @@ void renderNode(SceneNode* node, Gloom::Shader* parent_shader = default_shader) } } +// draw void renderFrame(GLFWwindow* window, int windowWidth, int windowHeight) { glViewport(0, 0, windowWidth, windowHeight); - renderNode(rootNode); - renderNode(hudNode); + // externs from scene.hpp, they must have shaders set + renderNode(rootNode, nullptr); + renderNode(hudNode, nullptr); } diff --git a/src/gamelogic.h b/src/gamelogic.hpp similarity index 56% rename from src/gamelogic.h rename to src/gamelogic.hpp index 8b09876..7895ffc 100644 --- a/src/gamelogic.h +++ b/src/gamelogic.hpp @@ -1,8 +1,12 @@ #pragma once - #include +#include #include +#include "sceneGraph.hpp" -void initGame(GLFWwindow* window, CommandLineOptions options); +// further divied into: +#include "scene.hpp" + +void initRenderer(GLFWwindow* window, CommandLineOptions options); void updateFrame(GLFWwindow* window, int windowWidth, int windowHeight); void renderFrame(GLFWwindow* window, int windowWidth, int windowHeight); diff --git a/src/program.cpp b/src/program.cpp index b11b7db..95d5e0c 100644 --- a/src/program.cpp +++ b/src/program.cpp @@ -1,7 +1,7 @@ // Local headers #include "program.hpp" #include "utilities/window.hpp" -#include "gamelogic.h" +#include "gamelogic.hpp" #include // glm::translate, glm::rotate, glm::scale, glm::perspective #include @@ -31,7 +31,7 @@ void runProgram(GLFWwindow* window, CommandLineOptions options) // Set default colour after clearing the colour buffer glClearColor(0.3f, 0.5f, 0.8f, 1.0f); - initGame(window, options); + initRenderer(window, options); // Rendering Loop while (!glfwWindowShouldClose(window)) diff --git a/src/scene.cpp b/src/scene.cpp new file mode 100644 index 0000000..f870f88 --- /dev/null +++ b/src/scene.cpp @@ -0,0 +1,190 @@ +#include "scene.hpp" +#include "gamelogic.hpp" +#include "sceneGraph.hpp" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using std::cout; +using std::endl; +typedef unsigned int uint; + +vec3 cameraPosition = vec3(0, 0, 400); +vec3 cameraLookAt = vec3(500, 500, 0); +vec3 cameraUpward = vec3(0, 0, 1); + +SceneNode* rootNode; +SceneNode* hudNode; +SceneNode* lightNode[N_LIGHTS]; + +SceneNode* plainNode; +SceneNode* carNode; +SceneNode* treeNode; +SceneNode* grassNode; +SceneNode* boxNode; +SceneNode* sphereNode; +SceneNode* textNode; + +Gloom::Shader* default_shader; +Gloom::Shader* plain_shader; +Gloom::Shader* post_shader; + +// todo: const the following: + +// meshes +Mesh m_box = generateBox(50, 50, 50); +Mesh m_sphere = generateSphere(10, 100, 100); +Mesh m_plain = generateSegmentedPlane(1000, 1000, 100, 100, 3); +Mesh m_hello_world = generateTextGeometryBuffer("Skjer'a bagera?", 1.3, 2); + +// textures +PNGImage t_charmap = loadPNGFile("../res/textures/charmap.png"); +PNGImage t_cobble_diff = loadPNGFile("../res/textures/cobble_diff.png"); +PNGImage t_cobble_normal = loadPNGFile("../res/textures/cobble_normal.png"); +PNGImage t_plain_diff = loadPNGFile("../res/textures/plain_diff.png"); +PNGImage t_plain_normal = loadPNGFile("../res/textures/plain_normal.png", true); +PNGImage t_reflection = loadPNGFile("../res/textures/reflection_field.png"); +PNGImage t_reflection2 = loadPNGFile("../res/textures/reflection_blurry.png"); +PNGImage t_perlin = makePerlinNoisePNG(256, 256, 0.05/16); + +void init_scene(CommandLineOptions options) { + default_shader = new Gloom::Shader(); + default_shader->makeBasicShader("../res/shaders/simple.vert", "../res/shaders/simple.frag"); + + rootNode = createSceneNode(); + hudNode = createSceneNode(); + rootNode->shader = default_shader; + hudNode->shader = default_shader; + + t_perlin.repeat_mirrored = true; // no const for me ;( + + // create and add lights to graph + for (uint i = 0; ilightID = i; + rootNode->children.push_back(lightNode[i]); + } + + //treeNode = loadModelScene("../res/models/fur_tree/scene.gltf"); + //treeNode->position = {300, 800, 10}; + //rootNode->children.push_back(treeNode); + + carNode = loadModelScene("../res/models/beetle/scene.gltf", { + { 0, Material().diffuse({0.0, 0.0, 1.0}).diffuse_only().reflection_mapped(&t_reflection, 0.15)},// Blue_Metal + { 1, Material().diffuse(vec3(0.85)).emissive(vec3(0.1)).reflection_mapped(&t_reflection, -1.0)},// Metal (decals) + //{ 2, Material().diffuse({1.0, 1.0, 1.0})},// Front_Light_Glass + // { 3, Material().diffuse({0.2, 0.2, 0.2})},// Black_Rubber + { 4, Material().no_colors().reflection_mapped(&t_reflection, 1.0)},// Mirror + //{ 5, Material().diffuse({1.0, 1.0, 1.0})},// Black_Metal + //{ 6, Material().diffuse({1.0, 1.0, 1.0})},// Plastic +// { 7, Material().diffuse(vec3(0.2)).emissive(vec3(0.25)).specular(vec3(1.0), 70).reflection_mapped(&t_reflection, -0.8)},// Window_Glass + { 7, Material().diffuse(vec3(0.2)).emissive(vec3(0.25)).specular(vec3(1.0), 70).reflection_mapped(&t_reflection, -0.8)},// Window_Glass + //{ 8, Material().diffuse({1.0, 1.0, 1.0})},// Material + { 9, Material().diffuse(vec3(1.0)).emissive(vec3(0.2)).specular(vec3(0.4), 70).reflection_mapped(&t_reflection, -1.0)},// Glossy_metal + //{10, Material().diffuse({1.0, 1.0, 1.0})},// Rogh_Metal +// {11, Material().no_colors().reflection_mapped(&t_reflection, 1.0)},// License_Plate_Metal + {11, Material().no_colors().reflection_mapped(&t_reflection, 1.0)},// License_Plate_Metal + //{12, Material().diffuse({1.0, 1.0, 1.0})},// License_Plate_Frame + //{13, Material().diffuse({1.0, 1.0, 1.0})},// + }); + //carNode->setMaterial(Material().reflection_mapped(&t_reflection, 0.0).no_colors().no_texture_reset(), true); + carNode->position = {500, 500, 100}; + carNode->scale *= 100; + rootNode->children.push_back(carNode); + + //create the scene: + plainNode = createSceneNode(); + plainNode->setTexture(&t_plain_diff, &t_plain_normal, &t_perlin); + plainNode->setMesh(&m_plain); + plainNode->position = {0, 0, 0}; + plainNode->shininess = 20; + plainNode->displacementCoefficient = 40; + rootNode->children.push_back(plainNode); + + /* + boxNode = createSceneNode(); + boxNode->setTexture(&t_cobble_diff, &t_cobble_normal); + boxNode->setMesh(&m_box); + boxNode->position = {500, 500, 40}; + boxNode->referencePoint = {25, 25, 25}; + boxNode->scale *= 2; + boxNode->shininess = 20; + boxNode->displacementCoefficient = 40; + rootNode->children.push_back(boxNode); + */ + + sphereNode = createSceneNode(); + //sphereNode->setTexture(&t_cobble_diff, &t_cobble_normal); + sphereNode->setMesh(&m_sphere); + sphereNode->position = {500, 500, 100}; + sphereNode->scale *= 15; + sphereNode->diffuse_color; + sphereNode->setMaterial(Material().reflection_mapped(&t_reflection, 0.5).no_colors().no_texture_reset(), true); + //rootNode->children.push_back(sphereNode); + + lightNode[0]->position = {-600, 1400, 800}; + lightNode[0]->attenuation = vec3(1.8, 0.0, 0.0); + + /* + lightNode[1]->position = {500, 0, 80}; + lightNode[1]->referencePoint = {0, 500, 0}; + lightNode[1]->scale *= 0.8; + lightNode[1]->light_color = vec3(0.0); + lightNode[1]->attenuation = vec3(1.0, 0.0, 0.000005); + + lightNode[2]->position = {400, -200, 300}; + lightNode[2]->nodeType = SPOT_LIGHT; + lightNode[2]->attenuation = vec3(1, 0, 0); + lightNode[2]->spot_target = lightNode[1]; + */ + + textNode = createSceneNode(); + textNode->setTexture(&t_charmap); + textNode->setMesh(&m_hello_world); + textNode->position = vec3(-1.0, -1.0, 0.0); + textNode->isIlluminated = false; + textNode->isInverted = true; + hudNode->children.push_back(textNode); +} + +void mouse_position_cb(double x, double y, int winw, int winh) { + float mousePositionX = x / double(winw); // like the hudNode space + float mousePositionY = y / double(winh); + +} + +void step_scene(double timeDelta) { + static double timeAcc = 0; // shrug + timeAcc += timeDelta; + + plainNode->uvOffset.x += timeDelta*0.5; + plainNode->uvOffset.y -= timeDelta*0.5; + if (boxNode) boxNode->rotation.z += timeDelta; + lightNode[1]->rotation.z -= timeDelta; + //lightNode[1]->position.z = 80 + 40*glm::sin(5 * lightNode[1]->rotation.z); + if(carNode) carNode->rotation.z += timeDelta; + + /* + if (glfwGetMouseButton(window, GLFW_MOUSE_BUTTON_1)) { + if (options.enableMusic) { + sound = new sf::Sound(); + sound->setBuffer(*buffer); + sf::Time startTime = sf::seconds(debug_startTime); + sound->setPlayingOffset(startTime); + sound->play(); + } + // I really should calculate this using the std::chrono timestamp for this + // You definitely end up with a cumulative error when doing lots of small additions like this + // However, for a game that lasts only a few minutes this is fine. + totalElapsedTime += timeDelta; + } + */ +} diff --git a/src/scene.hpp b/src/scene.hpp new file mode 100644 index 0000000..a374640 --- /dev/null +++ b/src/scene.hpp @@ -0,0 +1,18 @@ +#pragma once +#include +#include "sceneGraph.hpp" +#include "utilities/window.hpp" + +const uint N_LIGHTS = 3; + +extern SceneNode* rootNode; +extern SceneNode* hudNode; +extern SceneNode* lightNode[N_LIGHTS]; + +extern glm::vec3 cameraPosition; +extern glm::vec3 cameraLookAt; +extern glm::vec3 cameraUpward; + +void init_scene(CommandLineOptions options); +void mouse_position_cb(double x, double y, int winw, int winh); +void step_scene(double timeDelta);