#include "scene.hpp" #include "dbc.hpp" #include #include "skybox.hpp" #include void Scene::update() { float currentFrame = glfwGetTime(); deltaTime = currentFrame - lastFrame; lastFrame = currentFrame; // for now just detect the camera moved and do spotlight update if(camera.dirty) { light.camera.position = camera.position; light.camera.direction = camera.front; // just update the camera's light shader.apply_spot_light(light.camera, 0); camera.dirty = false; } camera.update(deltaTime); } void Scene::draw_thing(Shader& with_shader, Thing& thing) { with_shader.apply_material(thing.material); glm::mat4 model = glm::mat4(1.0f); model = glm::translate(model, thing.position); model = glm::rotate(model, glm::radians(thing.rotation.angle), thing.rotation.axes); model = glm::scale(model, glm::vec3(thing.scale)); with_shader.setMat4("model", model); // !reflect_on turns it on? yeah weird thing.model.draw(with_shader, !reflect_on, translations.size()); } void Scene::render(GLFWwindow* window) { glm::mat4 view = camera.look_at(); glm::mat4 projection = glm::mat4(1.0f); auto& with_shader = reflect_on ? reflect_shader : shader; // fov, aspect, near plane, far plane projection = glm::perspective(glm::radians(camera.fov), (float)SCR_WIDTH / (float)SCR_HEIGHT, 0.1f, 100.0f); framebuffer.begin(); // render the scene with_shader.use(); with_shader.setMat4("view", view); with_shader.setMat4("projection", projection); with_shader.setVec3("cameraPos", camera.position); with_shader.setFloat("time", glfwGetTime()); for(auto& thing : things) { draw_thing(with_shader, thing); } render_skybox(projection); framebuffer.commit(); framebuffer.draw(screen); } void Scene::cleanup() { shader.cleanup(); reflect_shader.cleanup(); skybox_shader.cleanup(); } void Scene::spawn(const std::string& name, components::Position& position, components::Rotation& rotation) { if(models.contains(name)) { translations.push_back(position); } else { dbc::log($F("No model named: {}", name)); } } void Scene::time_warp() { float time = glfwGetTime(); for(size_t i = 0; i < translations.size(); i++) { auto& t = translations[i]; float factor = (float)i / 3.0f; t.y = cos((time + i)) * factor; t.z = sin((time + i)) * factor; t.x = sin((time + i)) * factor; } glBindBuffer(GL_ARRAY_BUFFER, instanceVBO); glBufferData(GL_ARRAY_BUFFER, sizeof(glm::vec3) * translations.size(), translations.data(), GL_STATIC_DRAW); glBindBuffer(GL_ARRAY_BUFFER, 0); for(auto& mesh : things[0].model.meshes) { glBindVertexArray(mesh.VAO); glEnableVertexAttribArray(3); glBindBuffer(GL_ARRAY_BUFFER, instanceVBO); glVertexAttribPointer(3, 3, GL_FLOAT, GL_FALSE, sizeof(glm::vec3), (void*)0); glBindBuffer(GL_ARRAY_BUFFER, 0); glVertexAttribDivisor(3, 1); } } void Scene::setup_instancing() { for(size_t i = 0; i < INSTANCE_COUNT; i++) { translations.emplace_back((float)i, (float)i, (float)i); } time_warp(); } void Scene::init_skybox() { glBindVertexArray(skyboxVAO); glBindBuffer(GL_ARRAY_BUFFER, skyboxVBO); glBufferData(GL_ARRAY_BUFFER, sizeof(skyboxVertices), &skyboxVertices, GL_STATIC_DRAW); glEnableVertexAttribArray(0); glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0); load_skybox_textures(); } void Scene::load_skybox_textures() { int width = 0; int height = 0; int nrChannels = 0; size_t face_i = 0; glBindTexture(GL_TEXTURE_CUBE_MAP, skybox_texture_id); for(const auto& face : skybox_faces) { unsigned char *data = stbi_load(face.c_str(), &width, &height, &nrChannels, 0); dbc::check(data != nullptr, $F("Failed to load skybox face {}", face)); dbc::check(nrChannels == 3, $F("Skybox face {} must be RGB but you have {} channels", face, nrChannels)); glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + face_i, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, data); face_i++; stbi_image_free(data); } glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE); } void Scene::render_skybox(const glm::mat4& projection) { glDepthFunc(GL_LEQUAL); skybox_shader.use(); glm::mat4 view = glm::mat4(glm::mat3(camera.look_at())); skybox_shader.setMat4("view", view); skybox_shader.setMat4("projection", projection); glBindVertexArray(skyboxVAO); glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_CUBE_MAP, skybox_texture_id); glDrawArrays(GL_TRIANGLES, 0, 36); glBindVertexArray(0); glDepthFunc(GL_LESS); }