163 lines
4.8 KiB
C++
163 lines
4.8 KiB
C++
#include "scene.hpp"
|
|
#include "dbc.hpp"
|
|
#include <math.h>
|
|
#include "skybox.hpp"
|
|
#include <print>
|
|
|
|
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);
|
|
}
|