diff --git a/src/kekengine/cpp/kekengine.cpp b/src/kekengine/cpp/engine.cpp similarity index 50% rename from src/kekengine/cpp/kekengine.cpp rename to src/kekengine/cpp/engine.cpp index c0ac8a9..1f0fece 100644 --- a/src/kekengine/cpp/kekengine.cpp +++ b/src/kekengine/cpp/engine.cpp @@ -1,7 +1,4 @@ -#include "kekengine.h" -#include "errordialog.h" -#include "objparser.h" -#include "resource.h" +#include "engine.h" #include #include @@ -10,18 +7,23 @@ #include #include -namespace kek { +#include "internal.h" +#include "errordialog.h" +#include "objparser.h" +#include "resource.h" +#include "camera.h" +#include "constants.h" +#include "gameobject.h" +#include "scene.h" -static GLFWwindow *window; -static Camera *cam; +kek::KekData kek::kekData; -static int screenWidth = 800.0f; -static int screenHeight = 600.0f; +namespace kek::Engine { static void framebufferSizeCallback(GLFWwindow *window, int w, int h) { glViewport(0, 0, w, h); - screenWidth = w; - screenHeight = h; + kekData.screenWidth = w; + kekData.screenHeight = h; } static void glDebugOutput(GLenum source, GLenum type, unsigned int id, GLenum severity, GLsizei length, const char *message, const void *userParam) { @@ -47,8 +49,8 @@ void onCursorPosCallback(GLFWwindow *window, double x, double y) { xoff *= 0.1f; yoff *= 0.1f; - cam->rotateYaw(xoff); - cam->rotatePitch(yoff); + kekData.activeCamera->rotateYaw(xoff); + kekData.activeCamera->rotatePitch(yoff); } int init() { @@ -76,8 +78,10 @@ int init() { glfwWindowHint(GLFW_MAXIMIZED, GL_TRUE); glfwWindowHint(GLFW_OPENGL_DEBUG_CONTEXT, GL_TRUE); - window = glfwCreateWindow(screenWidth, screenHeight, "KekEngine", NULL, NULL); - if(window == NULL) { + kekData.screenWidth = 800.0f; + kekData.screenHeight = 600.0f; + kekData.window = glfwCreateWindow(kekData.screenWidth, kekData.screenHeight, "KekEngine", NULL, NULL); + if(!kekData.window) { const char *errorMsg; int code = glfwGetError(&errorMsg); if(code != GLFW_NO_ERROR) { @@ -90,7 +94,7 @@ int init() { return KEK_ERROR; } - glfwMakeContextCurrent(window); + glfwMakeContextCurrent(kekData.window); std::cout << "Initialized window" << std::endl; @@ -113,9 +117,9 @@ int init() { glDebugMessageControl(GL_DONT_CARE, GL_DONT_CARE, GL_DONT_CARE, 0, nullptr, GL_TRUE); } - glViewport(0, 0, screenWidth, screenHeight); + glViewport(0, 0, kekData.screenWidth, kekData.screenHeight); - glfwSetFramebufferSizeCallback(window, framebufferSizeCallback); + glfwSetFramebufferSizeCallback(kekData.window, framebufferSizeCallback); glEnable(GL_DEPTH_TEST); glEnable(GL_MULTISAMPLE); @@ -127,74 +131,84 @@ int init() { return KEK_ERROR; } - glfwSetCursorPosCallback(window, onCursorPosCallback); - glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_DISABLED); + glfwSetCursorPosCallback(kekData.window, onCursorPosCallback); + glfwSetInputMode(kekData.window, GLFW_CURSOR, GLFW_CURSOR_DISABLED); glClearColor(0.1f, 0.3f, 0.1f, 0.0f); - cam = new Camera(); + kekData.activeCamera = new Camera(); + kekData.shader = new Shader("shader/mesh/vertex.glsl", "shader/mesh/fragment.glsl"); - MemoryBuffer *buf = Resource::loadResource("object/sphere/Sphere.obj"); - Mesh *mesh = ObjParser::parse(buf); - Shader *shader = new Shader("shader/mesh/vertex.glsl", "shader/mesh/fragment.glsl"); - while(1) { + return KEK_SUCCESS; +} + +int start() { + while(!glfwWindowShouldClose(kekData.window)) { // Clear the screen glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - glViewport(0, 0, screenWidth, screenHeight); + glViewport(0, 0, kekData.screenWidth, kekData.screenHeight); - if(glfwGetKey(window, GLFW_KEY_W) == GLFW_PRESS) { - cam->translate(cam->direction * 0.1f); + for(std::pair cb : kekData.periodicCallbacks) { + cb.second(kekData.window); } - if(glfwGetKey(window, GLFW_KEY_S) == GLFW_PRESS) { - cam->translate(cam->direction * -0.1f); + if(glfwGetKey(kekData.window, GLFW_KEY_W) == GLFW_PRESS) { + kekData.activeCamera->translate(kekData.activeCamera->direction * 0.1f); } - if(glfwGetKey(window, GLFW_KEY_A) == GLFW_PRESS) { - glm::vec3 camRight = glm::normalize(glm::cross(cam->direction, glm::vec3(0.0f, 1.0f, 0.0f))); - cam->translate(-camRight * 0.1f); + if(glfwGetKey(kekData.window, GLFW_KEY_S) == GLFW_PRESS) { + kekData.activeCamera->translate(kekData.activeCamera->direction * -0.1f); } - if(glfwGetKey(window, GLFW_KEY_D) == GLFW_PRESS) { - glm::vec3 camRight = glm::normalize(glm::cross(cam->direction, glm::vec3(0.0f, 1.0f, 0.0f))); - cam->translate(camRight * 0.1f); + if(glfwGetKey(kekData.window, GLFW_KEY_A) == GLFW_PRESS) { + glm::vec3 camRight = glm::normalize(glm::cross(kekData.activeCamera->direction, glm::vec3(0.0f, 1.0f, 0.0f))); + kekData.activeCamera->translate(-camRight * 0.1f); } - if(glfwGetKey(window, GLFW_KEY_SPACE) == GLFW_PRESS) { - cam->translateY(0.1f); + if(glfwGetKey(kekData.window, GLFW_KEY_D) == GLFW_PRESS) { + glm::vec3 camRight = glm::normalize(glm::cross(kekData.activeCamera->direction, glm::vec3(0.0f, 1.0f, 0.0f))); + kekData.activeCamera->translate(camRight * 0.1f); } - if(glfwGetKey(window, GLFW_KEY_LEFT_CONTROL) == GLFW_PRESS) { - cam->translateY(-0.1f); + if(glfwGetKey(kekData.window, GLFW_KEY_SPACE) == GLFW_PRESS) { + kekData.activeCamera->translateY(0.1f); } - if(glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS) { + if(glfwGetKey(kekData.window, GLFW_KEY_LEFT_CONTROL) == GLFW_PRESS) { + kekData.activeCamera->translateY(-0.1f); + } + + if(glfwGetKey(kekData.window, GLFW_KEY_ESCAPE) == GLFW_PRESS) { break; } - shader->use(); + kekData.shader->use(); - glm::mat4 view = cam->transformationMatrix(); + glm::mat4 view = kekData.activeCamera->transformationMatrix(); glm::mat4 projection; - projection = glm::perspective(glm::radians(90.0f), screenWidth / (float) screenHeight, KEK_CAMERA_NEAR, KEK_CAMERA_FAR); + projection = glm::perspective(glm::radians(90.0f), kekData.screenWidth / (float) kekData.screenHeight, KEK_CAMERA_NEAR, KEK_CAMERA_FAR); - glm::vec3 position = cam->getPosition(); + glm::vec3 position = kekData.activeCamera->getPosition(); - glUniformMatrix4fv(glGetUniformLocation(shader->id, "view"), 1, GL_FALSE, glm::value_ptr(view)); - glUniformMatrix4fv(glGetUniformLocation(shader->id, "projection"), 1, GL_FALSE, glm::value_ptr(projection)); - glUniform3fv(glGetUniformLocation(shader->id, "cameraPos"), 1, glm::value_ptr(position)); + glUniformMatrix4fv(glGetUniformLocation(kekData.shader->id, "view"), 1, GL_FALSE, glm::value_ptr(view)); + glUniformMatrix4fv(glGetUniformLocation(kekData.shader->id, "projection"), 1, GL_FALSE, glm::value_ptr(projection)); + glUniform3fv(glGetUniformLocation(kekData.shader->id, "cameraPos"), 1, glm::value_ptr(position)); glm::mat4 model = glm::mat4(1.0f); - glUniformMatrix4fv(glGetUniformLocation(shader->id, "model"), 1, GL_FALSE, glm::value_ptr(model)); + glUniformMatrix4fv(glGetUniformLocation(kekData.shader->id, "model"), 1, GL_FALSE, glm::value_ptr(model)); - mesh->draw(shader); + if(kekData.activeScene) kekData.activeScene->draw(kekData.shader); // Swap buffers and poll window events - glfwSwapBuffers(window); + glfwSwapBuffers(kekData.window); glfwPollEvents(); } return KEK_SUCCESS; } +void setActiveScene(Scene *scene) { + kekData.activeScene = scene; +} + } diff --git a/src/kekengine/cpp/gameobject.cpp b/src/kekengine/cpp/gameobject.cpp new file mode 100644 index 0000000..4c81e44 --- /dev/null +++ b/src/kekengine/cpp/gameobject.cpp @@ -0,0 +1,25 @@ +#include "gameobject.h" + +namespace kek { + +GameObject::GameObject() { + +} + +GameObject::~GameObject() { + for(Mesh *mesh : meshes) { + delete mesh; + } +} + +void GameObject::addMesh(Mesh *mesh) { + meshes.push_back(mesh); +} + +void GameObject::draw(Shader *shader) { + for(Mesh *mesh : meshes) { + mesh->draw(shader); + } +} + +} diff --git a/src/kekengine/cpp/input.cpp b/src/kekengine/cpp/input.cpp new file mode 100644 index 0000000..aa19341 --- /dev/null +++ b/src/kekengine/cpp/input.cpp @@ -0,0 +1,41 @@ +#include "input.h" + +#include + +#include "internal.h" + +namespace kek::Input { + +static InputListener nextID = 0; + +InputListener addPeriodicCallback(PeriodicCallback callback) { + InputListener id = nextID++; + kekData.periodicCallbacks.emplace(id, callback); + return id; +} + +void removePeriodicCallback(InputListener listener) { + kekData.periodicCallbacks.erase(listener); +} + +InputListener addKeyListener(KeyCallback callback) { + InputListener id = nextID++; + kekData.keyCallbacks.emplace(id, callback); + return id; +} + +void removeKeyListener(InputListener listener) { + kekData.keyCallbacks.erase(listener); +} + +InputListener addMouseListener(MouseCallback callback) { + InputListener id = nextID++; + kekData.mouseCallbacks.emplace(id, callback); + return id; +} + +void removeMouseListener(InputListener listener) { + kekData.mouseCallbacks.erase(listener); +} + +} diff --git a/src/kekengine/cpp/mesh.cpp b/src/kekengine/cpp/mesh.cpp index 3cc4a9c..3fa7758 100644 --- a/src/kekengine/cpp/mesh.cpp +++ b/src/kekengine/cpp/mesh.cpp @@ -59,7 +59,7 @@ void Mesh::draw(Shader *shader) { glBindBuffer(GL_ARRAY_BUFFER, vbo); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ebo); - /*if(!light) { + /*if(!light) { // TODO: check if props exist material->diffuse->use(GL_TEXTURE0); glUniform1i(glGetUniformLocation(shader->id, "material.diffuse"), 0); diff --git a/src/kekengine/cpp/objparser.cpp b/src/kekengine/cpp/objparser.cpp index d58dc46..7d30b69 100644 --- a/src/kekengine/cpp/objparser.cpp +++ b/src/kekengine/cpp/objparser.cpp @@ -4,7 +4,6 @@ #include #include #include -#include #include "types.h" diff --git a/src/kekengine/cpp/scene.cpp b/src/kekengine/cpp/scene.cpp new file mode 100644 index 0000000..a662fa1 --- /dev/null +++ b/src/kekengine/cpp/scene.cpp @@ -0,0 +1,33 @@ +#include "scene.h" + +namespace kek { + +Scene::Scene() { + +} + +Scene::~Scene() { + for(GameObject *obj : objects) delete obj; +} + +void Scene::addObject(GameObject *object) { + objects.push_back(object); +} + +void Scene::removeObject(GameObject *object) { + for(auto it = objects.begin(); it < objects.end(); it++) { + if(*it == object) { + objects.erase(it); + delete object; + break; + } + } +} + +void Scene::draw(Shader *shader) { + for(GameObject *obj : objects) { + obj->draw(shader); + } +} + +} diff --git a/src/kekengine/cpp/shader.cpp b/src/kekengine/cpp/shader.cpp index 7e8b112..a97b300 100644 --- a/src/kekengine/cpp/shader.cpp +++ b/src/kekengine/cpp/shader.cpp @@ -13,10 +13,25 @@ static GLuint compileShader(GLenum type, std::string path) { throw std::exception(); } + std::istream inStream(buf); std::ostringstream stream; - stream << buf; - std::string code = stream.str(); + std::string line; + while(std::getline(inStream, line)) { + if(line.find("!include ") == 0) { + std::string includePath = line.substr(9); + MemoryBuffer *includeBuf = Resource::loadResource("shader/include/" + includePath); + if(!includeBuf) { + std::cerr << "Include error: Failed to find path '" << includePath << "'" << std::endl; + throw std::exception(); + } + stream << includeBuf; + delete includeBuf; + }else { + stream << line << '\n'; + } + } + std::string code = stream.str(); delete buf; const char *src = code.c_str(); diff --git a/src/kekengine/include/engine.h b/src/kekengine/include/engine.h new file mode 100644 index 0000000..92f71ca --- /dev/null +++ b/src/kekengine/include/engine.h @@ -0,0 +1,13 @@ +#pragma once + +#include "scene.h" + +namespace kek::Engine { + +int init(); + +int start(); + +void setActiveScene(Scene *scene); + +} diff --git a/src/kekengine/include/gameobject.h b/src/kekengine/include/gameobject.h new file mode 100644 index 0000000..3dafe1b --- /dev/null +++ b/src/kekengine/include/gameobject.h @@ -0,0 +1,25 @@ +#pragma once + +#include "object.h" +#include "mesh.h" + +namespace kek { + +class GameObject: public DefaultRotateableObject { + +protected: + std::vector meshes; + +public: + GameObject(); + + ~GameObject(); + + // Adds a mesh to the GameObject. The GameObject takes ownership of the Mesh, so don't use Meshes in multiple GameObjects + void addMesh(Mesh *mesh); + + void draw(Shader *shader); + +}; + +} diff --git a/src/kekengine/include/input.h b/src/kekengine/include/input.h new file mode 100644 index 0000000..a2b3d38 --- /dev/null +++ b/src/kekengine/include/input.h @@ -0,0 +1,31 @@ +#pragma once + +#include + +#include "utils.h" + +namespace kek { + +typedef generic_callable_t PeriodicCallback; +typedef generic_callable_t KeyCallback; +typedef generic_callable_t MouseCallback; + +typedef unsigned int InputListener; + +} + +namespace kek::Input { + +InputListener addPeriodicCallback(PeriodicCallback callback); + +void removePeriodicCallback(InputListener listener); + +InputListener addKeyListener(KeyCallback callback); + +void removeKeyListener(InputListener listener); + +InputListener addMouseListener(MouseCallback callback); + +void removeMouseListener(InputListener listener); + +} diff --git a/src/kekengine/include/internal.h b/src/kekengine/include/internal.h new file mode 100644 index 0000000..84fff74 --- /dev/null +++ b/src/kekengine/include/internal.h @@ -0,0 +1,28 @@ +#pragma once + +#include "input.h" +#include "camera.h" +#include "scene.h" + +#include + +namespace kek { + +struct KekData { + std::map periodicCallbacks; + std::map keyCallbacks; + std::map mouseCallbacks; + + GLFWwindow *window; + Shader *shader; + + Camera *activeCamera; + Scene *activeScene; + + int screenWidth; + int screenHeight; +}; + +extern KekData kekData; + +} diff --git a/src/kekengine/include/kekengine.h b/src/kekengine/include/kekengine.h index a4b0657..d6cd7ec 100644 --- a/src/kekengine/include/kekengine.h +++ b/src/kekengine/include/kekengine.h @@ -2,17 +2,14 @@ #include "camera.h" #include "constants.h" +#include "engine.h" #include "errordialog.h" +#include "gameobject.h" #include "mesh.h" #include "object.h" #include "objparser.h" #include "resource.h" +#include "scene.h" #include "shader.h" #include "types.h" #include "utils.h" - -namespace kek { - -int init(); - -} diff --git a/src/kekengine/include/scene.h b/src/kekengine/include/scene.h new file mode 100644 index 0000000..9a62787 --- /dev/null +++ b/src/kekengine/include/scene.h @@ -0,0 +1,30 @@ +#pragma once + +#include + +#include "gameobject.h" + +namespace kek { + +class Scene { + +protected: + std::vector objects; + +public: + Scene(); + + ~Scene(); + + // Adds an object to the scene. The scene will take ownership of the object + void addObject(GameObject *object); + + // Removes an object from the scene. The object will be deleted + void removeObject(GameObject *object); + + // Draws the scene + void draw(Shader *shader); + +}; + +} diff --git a/src/kekengine/include/utils.h b/src/kekengine/include/utils.h index 1564f74..82a8add 100644 --- a/src/kekengine/include/utils.h +++ b/src/kekengine/include/utils.h @@ -43,4 +43,4 @@ std::vector genCubeVertices(float w, float h, float d, bool texCoords); std::string toString(glm::vec3 vector); -} \ No newline at end of file +} diff --git a/src/kekengine/res/shader/include/types.glsl b/src/kekengine/res/shader/include/types.glsl new file mode 100644 index 0000000..fdf9831 --- /dev/null +++ b/src/kekengine/res/shader/include/types.glsl @@ -0,0 +1,44 @@ +struct Material { + sampler2D diffuse; + sampler2D specular; + float shininess; +}; + +struct PointLight { + vec3 position; + + vec3 ambient; + vec3 diffuse; + vec3 specular; + + float constant; + float linear; + float quadratic; +}; + +struct DirectionalLight { + vec3 direction; + + vec3 ambient; + vec3 diffuse; + vec3 specular; + + mat4 lightSpaceMatrix; +}; + +struct SpotLight { + vec3 position; + vec3 direction; + float innerCutOff; + float outerCutOff; + + vec3 ambient; + vec3 diffuse; + vec3 specular; + + float constant; + float linear; + float quadratic; + + mat4 lightSpaceMatrix; +}; diff --git a/src/kekengine/res/shader/mesh/fragment.glsl b/src/kekengine/res/shader/mesh/fragment.glsl index b29b2e5..eba990c 100644 --- a/src/kekengine/res/shader/mesh/fragment.glsl +++ b/src/kekengine/res/shader/mesh/fragment.glsl @@ -1,5 +1,7 @@ #version 330 core +!include types.glsl + in VS_OUT { vec3 fragmentPosition; vec2 textureCoordinate; diff --git a/src/kekengine/res/shader/mesh/vertex.glsl b/src/kekengine/res/shader/mesh/vertex.glsl index bbc5871..f4deb40 100644 --- a/src/kekengine/res/shader/mesh/vertex.glsl +++ b/src/kekengine/res/shader/mesh/vertex.glsl @@ -1,5 +1,7 @@ #version 330 core +!include types.glsl + layout (location = 0) in vec3 position; layout (location = 1) in vec3 normal; layout (location = 2) in vec2 texCoord; diff --git a/src/kekgame/cpp/kekgame.cpp b/src/kekgame/cpp/kekgame.cpp index 4657ad9..b8a5173 100644 --- a/src/kekgame/cpp/kekgame.cpp +++ b/src/kekgame/cpp/kekgame.cpp @@ -4,6 +4,21 @@ #include #include +using namespace kek; + int main(int argc, char **argv) { - kek::init(); + Engine::init(); + + MemoryBuffer *buf = Resource::loadResource("object/sphere/Sphere.obj"); + Mesh *mesh = ObjParser::parse(buf); + delete buf; + + GameObject *test = new GameObject(); + test->addMesh(mesh); + + Scene *scene = new Scene(); + scene->addObject(test); + Engine::setActiveScene(scene); + + Engine::start(); }