#include "glad/gl.h" #include "GLFW/glfw3.h" #include "spdlog/spdlog.h" #include "glm/glm.hpp" #include "glm/ext/matrix_clip_space.hpp" #define STB_IMAGE_IMPLEMENTATION #include "stb_image.h" #include "Camera.h" #include "Components.h" #include "EditorContext.h" #include "FreeCameraController.h" #include "InputManager.h" #include "ModelManager.h" #include "Scene.h" #include "ShaderManager.h" #include "ShaderProgram.h" #include "TextureManager.h" #include "UIManager.h" #include "ui/UIEntityInspector.h" #include "ui/UIMenuBar.h" #include "ui/UISceneGraph.h" #include "ui/UISceneViewer.h" GLFWwindow* gWindow = nullptr; int gWindowWidth = 1920; int gWindowHeight = 1080; int glVersionMajor = 0; int glVersionMinor = 0; float gAspectRatio = 0.f; float gMouseSensitivity = 0.1f; Camera gCamera {}; Scene gScene{}; EditorContext gEditorCtx{}; FreeCameraController gCameraController{}; void glfw_error_callback(int error, const char* description); void glfw_key_callback(GLFWwindow* window, int key, int scancode, int action, int mods); void glfw_framebuffer_size_callback(GLFWwindow* window, int width, int height); void init_glfw(); void create_main_window(); void load_gl(); void init_camera(); void init_scene(); void load_default_textures(); void load_shaders(); void load_inputs(); void load_default_models(); void loop(); void create_entity(entt::entity parent); auto xAxis = glm::vec3{1.f, 0.f, 0.f}; auto yAxis = glm::vec3{0.f, 1.f, 0.f}; auto zAxis = glm::vec3{0.f, 0.f, 1.f}; int main() { spdlog::info("b_engine v0.0.3 start"); init_glfw(); create_main_window(); load_gl(); stbi_set_flip_vertically_on_load(true); load_default_textures(); load_shaders(); load_inputs(); load_default_models(); UIManager::init(gWindow); UIMenuBar* menuBar = UIManager::add_ui_panel("menu_bar"); menuBar->create_entity = create_entity; UIManager::add_ui_panel("scene_viewer"); UIManager::add_ui_panel("scene_graph"); UIManager::add_ui_panel("entity_inspector"); init_camera(); init_scene(); gCameraController.set_camera(gCamera); gCameraController.look_sensitivity = 0.2; gCameraController.movement_speed = 0.2; InputManager::add_mouse_listener([](float xoff, float yoff) { gCameraController.on_mouse_delta(xoff, yoff); }); gEditorCtx.scene = &gScene; gEditorCtx.window = gWindow; gEditorCtx.selectedEntity = entt::null; loop(); ShaderManager::shaders.clear(); TextureManager::textures.clear(); ModelManager::models.clear(); glfwDestroyWindow(gWindow); glfwTerminate(); return 0; } void glfw_error_callback(int error, const char* description) { spdlog::error("glfw error: {}", description); } void glfw_framebuffer_size_callback(GLFWwindow *window, int width, int height) { glViewport(0, 0, width, height); gAspectRatio = (float)width / (float)height; gCamera.update_aspect_ratio(gAspectRatio); } void init_glfw() { if (!glfwInit()) { spdlog::error("could not initialize glfw"); std::exit(1); } glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4); glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 0); glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); glfwWindowHint(GLFW_SAMPLES, 4); glfwSetErrorCallback(glfw_error_callback); } void create_main_window() { gWindow = glfwCreateWindow(gWindowWidth, gWindowHeight, "b_engine v0.0.3", nullptr, nullptr); if (!gWindow) { spdlog::error("failed to create glfw window"); std::exit(1); } glfwMakeContextCurrent(gWindow); glfwSetKeyCallback(gWindow, InputManager::key_callback); glfwSetCursorPosCallback(gWindow, InputManager::mouse_pos_callback); glfwSetFramebufferSizeCallback(gWindow, glfw_framebuffer_size_callback); #ifndef GLFW_CONTEXT_DEBUG glfwSetInputMode(gWindow, GLFW_CURSOR, GLFW_CURSOR_DISABLED); #endif } void load_gl() { int version = gladLoadGL(glfwGetProcAddress); glVersionMajor = GLAD_VERSION_MAJOR(version); glVersionMinor = GLAD_VERSION_MINOR(version); spdlog::info("gl version {}.{}", glVersionMajor, glVersionMinor); if (gWindow) { int fbWidth, fbHeight; glfwGetFramebufferSize(gWindow, &fbWidth, &fbHeight); gAspectRatio = (float)fbWidth / (float)fbHeight; } glEnable(GL_DEPTH_TEST); glEnable(GL_MULTISAMPLE); } void init_camera() { gCamera = {{10.f, 10.f, 10.f}, 0, 0, gAspectRatio}; gCamera.rotate_yaw(-135.f); gCamera.rotate_pitch(-35.f); } void init_scene() { gScene.set_active_camera(&gCamera); const auto defaultLight = gScene.create_game_object(); auto& [name] = gScene.fetch_component(defaultLight); name = "Directional Light"; auto& [direction, ambient, diffuse, specular] = gScene.attach_component(defaultLight); direction = glm::vec3(-1, -1, -1); ambient = glm::vec3(0.3); diffuse = glm::vec3(0.7); specular = glm::vec3(1.0); } void load_default_textures() { spdlog::info("creating default textures"); unsigned char defaultDiffuseData[4] = {static_cast(255), 255, 255, 255}; TextureManager::textures["default_diffuse"] = TextureManager::load_from_data(reinterpret_cast(&defaultDiffuseData), 1, 1, 4); unsigned char defaultSpecularData[4] = {static_cast(64), 64, 64, 255}; TextureManager::textures["default_specular"] = TextureManager::load_from_data(reinterpret_cast(&defaultSpecularData), 1, 1, 4); } void load_shaders() { spdlog::info("compiling shaders"); ShaderManager::shaders["phong_shader"] = ShaderManager::load("./resources/standard.vert", "./resources/standard.frag"); if (ShaderManager::shaders["phong_shader"] == nullptr) { spdlog::error("failed to compile phong shader"); std::exit(1); } } void load_inputs() { InputManager::generate_input_action("move_forward", {{GLFW_KEY_W, KEY_DOWN}}); InputManager::generate_input_action("move_backward", {{GLFW_KEY_S, KEY_DOWN}}); InputManager::generate_input_action("move_right", {{GLFW_KEY_D, KEY_DOWN}}); InputManager::generate_input_action("move_left", {{GLFW_KEY_A, KEY_DOWN}}); InputManager::generate_input_action("move_up", {{GLFW_KEY_SPACE, KEY_DOWN}}); InputManager::generate_input_action("move_down", {{GLFW_KEY_LEFT_SHIFT, KEY_DOWN}}); } void load_default_models() { spdlog::info("loading default models"); ModelManager::models["cube"] = ModelManager::load_from_file("./resources/cube.obj"); ModelManager::models["vette"] = ModelManager::load_from_file("./resources/c4/C4Fixed.obj"); ModelManager::models["male"] = ModelManager::load_from_file("./resources/male.obj"); } void loop() { while (!glfwWindowShouldClose(gWindow)) { // input glfwPollEvents(); // update UIManager::update(gEditorCtx); gCameraController.update(gEditorCtx); if (gCamera.aspect_ratio() != gEditorCtx.viewportAspectRatio) { gCamera.update_aspect_ratio(gEditorCtx.viewportAspectRatio); } gScene.update_transforms(); const auto* uiScenePanel = dynamic_cast(UIManager::get_ui_panel("scene_viewer").get()); if (uiScenePanel) { uiScenePanel->bind_fbo(); } // draw glClearColor(0.2f, 0.3f, 0.3f, 1.0f); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); const auto shader = ShaderManager::shaders["phong_shader"]; gScene.draw_scene(shader.get()); glBindVertexArray(0); ShaderProgram::unbind(); glBindFramebuffer(GL_FRAMEBUFFER, 0); UIManager::draw(); // end frame glfwSwapBuffers(gWindow); } } void create_entity(entt::entity parent) { auto entity = gScene.create_game_object(parent); auto& drawable = gScene.attach_component(entity); drawable.model = ModelManager::models["vette"]; auto& transform = gScene.fetch_component(entity); transform.scale = {0.1, 0.1, 0.1}; transform.dirty = true; }