feat: engine as library
This commit is contained in:
61
engine/src/renderer/debug.cpp
Normal file
61
engine/src/renderer/debug.cpp
Normal file
@ -0,0 +1,61 @@
|
||||
#include "engine/renderer/debug.h"
|
||||
|
||||
#include <iostream>
|
||||
|
||||
void MessageCallback(GLenum source,
|
||||
GLenum type,
|
||||
GLuint id,
|
||||
GLenum severity,
|
||||
GLsizei length,
|
||||
const GLchar* message,
|
||||
const void* userParam)
|
||||
{
|
||||
if(id == 131169 || id == 131185 || id == 131218 || id == 131204) return;
|
||||
|
||||
std::cout << "---------------" << std::endl;
|
||||
std::cout << "Debug message (" << id << "): " << message << std::endl;
|
||||
|
||||
switch (source)
|
||||
{
|
||||
case GL_DEBUG_SOURCE_API: std::cout << "Source: API"; break;
|
||||
case GL_DEBUG_SOURCE_WINDOW_SYSTEM: std::cout << "Source: Window System"; break;
|
||||
case GL_DEBUG_SOURCE_SHADER_COMPILER: std::cout << "Source: Shader Compiler"; break;
|
||||
case GL_DEBUG_SOURCE_THIRD_PARTY: std::cout << "Source: Third Party"; break;
|
||||
case GL_DEBUG_SOURCE_APPLICATION: std::cout << "Source: Application"; break;
|
||||
case GL_DEBUG_SOURCE_OTHER: std::cout << "Source: Other"; break;
|
||||
} std::cout << std::endl;
|
||||
|
||||
switch (type)
|
||||
{
|
||||
case GL_DEBUG_TYPE_ERROR: std::cout << "Type: Error"; break;
|
||||
case GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR: std::cout << "Type: Deprecated Behaviour"; break;
|
||||
case GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR: std::cout << "Type: Undefined Behaviour"; break;
|
||||
case GL_DEBUG_TYPE_PORTABILITY: std::cout << "Type: Portability"; break;
|
||||
case GL_DEBUG_TYPE_PERFORMANCE: std::cout << "Type: Performance"; break;
|
||||
case GL_DEBUG_TYPE_MARKER: std::cout << "Type: Marker"; break;
|
||||
case GL_DEBUG_TYPE_PUSH_GROUP: std::cout << "Type: Push Group"; break;
|
||||
case GL_DEBUG_TYPE_POP_GROUP: std::cout << "Type: Pop Group"; break;
|
||||
case GL_DEBUG_TYPE_OTHER: std::cout << "Type: Other"; break;
|
||||
} std::cout << std::endl;
|
||||
|
||||
switch (severity)
|
||||
{
|
||||
case GL_DEBUG_SEVERITY_HIGH: std::cout << "Severity: high"; break;
|
||||
case GL_DEBUG_SEVERITY_MEDIUM: std::cout << "Severity: medium"; break;
|
||||
case GL_DEBUG_SEVERITY_LOW: std::cout << "Severity: low"; break;
|
||||
case GL_DEBUG_SEVERITY_NOTIFICATION: std::cout << "Severity: notification"; break;
|
||||
} std::cout << std::endl;
|
||||
std::cout << std::endl;
|
||||
return;
|
||||
(void) source;
|
||||
(void) id;
|
||||
(void) length;
|
||||
(void) userParam;
|
||||
std::cerr << "GL CALLBACK: " << (type == GL_DEBUG_TYPE_ERROR ? "** GL ERROR **" : "")
|
||||
<< " type = 0x" << type
|
||||
<< ", severity = 0x" << severity
|
||||
<< ", message = " << message << std::endl;
|
||||
// std::cerr << "GL CALLBACK: %s type = 0x%x, severity = 0x%x, message = %s\n",
|
||||
// (type == GL_DEBUG_TYPE_ERROR ? "** GL ERROR **" : ""),
|
||||
// type, severity, message);
|
||||
}
|
42
engine/src/renderer/engine.cpp
Normal file
42
engine/src/renderer/engine.cpp
Normal file
@ -0,0 +1,42 @@
|
||||
#include <memory>
|
||||
|
||||
#include "engine/renderer/engine.h"
|
||||
#include "engine/window/event.h"
|
||||
|
||||
#include "engine/renderer/wavefront.h"
|
||||
|
||||
std::unique_ptr<IApplication> Engine::s_app = nullptr;
|
||||
std::shared_ptr<Window> Engine::s_window = nullptr;
|
||||
bool Engine::s_running = false;
|
||||
|
||||
void Engine::Run(std::unique_ptr<IApplication> app) {
|
||||
s_app = std::move(app);
|
||||
s_window = Window::GetInstance();
|
||||
s_running = true;
|
||||
|
||||
s_app->OnInit();
|
||||
|
||||
s_window->Subscribe<WindowCloseRequested>([](const WindowCloseRequested& e) {
|
||||
Engine::s_running = false;
|
||||
});
|
||||
|
||||
s_window->Subscribe<WindowResized>([](const WindowResized& e) {
|
||||
Engine::s_app->OnWindowResized(e);
|
||||
});
|
||||
|
||||
while (s_running) {
|
||||
s_window->ProcessEvents();
|
||||
|
||||
s_app->OnUpdate();
|
||||
|
||||
s_app->OnRender();
|
||||
|
||||
s_window->SwapBuffers();
|
||||
}
|
||||
|
||||
s_app->OnShutdown();
|
||||
|
||||
s_window->Destroy();
|
||||
s_app.reset();
|
||||
}
|
||||
|
60
engine/src/renderer/mesh.cpp
Normal file
60
engine/src/renderer/mesh.cpp
Normal file
@ -0,0 +1,60 @@
|
||||
#include <cstddef>
|
||||
|
||||
#include "engine/renderer/mesh.h"
|
||||
|
||||
Mesh::Mesh() {
|
||||
m_vao = 0;
|
||||
m_vbo = 0;
|
||||
m_ebo = 0;
|
||||
|
||||
glGenVertexArrays(1, &m_vao);
|
||||
glGenBuffers(1, &m_vbo);
|
||||
glGenBuffers(1, &m_ebo);
|
||||
|
||||
glBindVertexArray(m_vao);
|
||||
|
||||
// VBO (vertex buffer)
|
||||
glBindBuffer(GL_ARRAY_BUFFER, m_vbo);
|
||||
glBufferData(GL_ARRAY_BUFFER, 0, nullptr, GL_DYNAMIC_DRAW);
|
||||
|
||||
// EBO (index buffer)
|
||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_ebo);
|
||||
glBufferData(GL_ELEMENT_ARRAY_BUFFER, 0, nullptr, GL_DYNAMIC_DRAW);
|
||||
|
||||
// attributes
|
||||
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), reinterpret_cast<const void*>(offsetof(Vertex, m_position)));
|
||||
glEnableVertexAttribArray(0);
|
||||
|
||||
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), reinterpret_cast<const void*>(offsetof(Vertex, m_normal)));
|
||||
glEnableVertexAttribArray(1);
|
||||
|
||||
glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), reinterpret_cast<const void*>(offsetof(Vertex, m_texCoord)));
|
||||
glEnableVertexAttribArray(2);
|
||||
|
||||
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
||||
glBindVertexArray(0);
|
||||
}
|
||||
|
||||
void Mesh::Upload() const {
|
||||
glBindVertexArray(m_vao);
|
||||
|
||||
glBindBuffer(GL_ARRAY_BUFFER, m_vbo);
|
||||
glBufferData(GL_ARRAY_BUFFER, m_vertexBuffer.size() * sizeof(Vertex), m_vertexBuffer.data(), GL_DYNAMIC_DRAW);
|
||||
|
||||
// Upload indices
|
||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_ebo);
|
||||
glBufferData(GL_ELEMENT_ARRAY_BUFFER, m_indexBuffer.size() * sizeof(unsigned int), m_indexBuffer.data(), GL_DYNAMIC_DRAW);
|
||||
|
||||
glBindVertexArray(0);
|
||||
}
|
||||
|
||||
void Mesh::Render(unsigned int count)
|
||||
{
|
||||
Bind();
|
||||
if (count > 1) {
|
||||
glDrawElementsInstanced(GL_TRIANGLES, static_cast<GLsizei>(m_indexBuffer.size()), GL_UNSIGNED_INT, 0, count);
|
||||
} else {
|
||||
glDrawElements(GL_TRIANGLES, static_cast<GLsizei>(m_indexBuffer.size()), GL_UNSIGNED_INT, 0);
|
||||
}
|
||||
Unbind();
|
||||
}
|
246
engine/src/renderer/renderer.cpp
Normal file
246
engine/src/renderer/renderer.cpp
Normal file
@ -0,0 +1,246 @@
|
||||
#include <iostream>
|
||||
#include <cassert>
|
||||
#include <glm/glm.hpp>
|
||||
#include <glm/ext/matrix_clip_space.hpp>
|
||||
#ifdef WIN32
|
||||
#include <corecrt_math_defines.h>
|
||||
#endif
|
||||
#include <glm/ext/matrix_transform.hpp>
|
||||
#define GLM_ENABLE_EXPERIMENTAL
|
||||
#include <glm/gtx/euler_angles.hpp>
|
||||
|
||||
#include "engine/renderer/renderer.h"
|
||||
#include "engine/window/window.h"
|
||||
#include "engine/IO/file_manager.h"
|
||||
|
||||
#include "engine/components/transform.h"
|
||||
#include "engine/components/camera.h"
|
||||
#include "engine/components/light.h"
|
||||
#include "engine/components/mesh.h"
|
||||
#include "engine/components/batch.h"
|
||||
|
||||
Renderer::Renderer(entt::registry& registry) : m_registry(registry)
|
||||
{
|
||||
m_proj = glm::perspective(
|
||||
static_cast<float>(M_PI_2),
|
||||
static_cast<float>(Window::GetWidth()) / static_cast<float>(Window::GetHeight()),
|
||||
0.01f,
|
||||
100.0f
|
||||
);
|
||||
|
||||
m_shader.init(
|
||||
FileManager::read("./src/shaders/main.vs"),
|
||||
FileManager::read("./src/shaders/pbr.fs")
|
||||
);
|
||||
|
||||
m_depthShader.init(
|
||||
FileManager::read("./src/shaders/depth.vs"),
|
||||
FileManager::read("./src/shaders/depth.fs")
|
||||
);
|
||||
|
||||
m_model = glm::mat4(1.f);
|
||||
|
||||
m_shader.use();
|
||||
m_shader.setMat4("u_projection", m_proj);
|
||||
}
|
||||
|
||||
void Renderer::Init() {
|
||||
// auto view = m_registry.view<batch, mesh>();
|
||||
// for (auto [_, b, m] : m_registry.view<batch, mesh>().each()) {
|
||||
// unsigned int items = 0;
|
||||
// for (auto [entt, item] : m_registry.view<batch::item>().each()) {
|
||||
// if (item.batchId == b.id()) ++items;
|
||||
// }
|
||||
// b.prepare()
|
||||
// m.object->EnableBatch(b.m_instance_vbo);
|
||||
// }
|
||||
}
|
||||
|
||||
void Renderer::OnWindowResized(int w, int h) {
|
||||
m_proj = glm::perspective(
|
||||
static_cast<float>(M_PI_2),
|
||||
static_cast<float>(w) / static_cast<float>(h),
|
||||
0.01f,
|
||||
100.0f
|
||||
);
|
||||
}
|
||||
|
||||
void Renderer::ApplyLights(Shader &shader) {
|
||||
auto lights = m_registry.view<light>();
|
||||
// TODO: Pass Lights Data to depth shader as well
|
||||
shader.setInt("lightsCount", static_cast<int>(lights.size()));
|
||||
size_t lightIndex = 0;
|
||||
for (auto entity : lights) {
|
||||
auto &l = m_registry.get<light>(entity);
|
||||
auto &transf = m_registry.get<transform>(entity);
|
||||
|
||||
shader.setInt("lights[" + std::to_string(lightIndex) + "].type", static_cast<int>(l.type));
|
||||
shader.setVec3("lights[" + std::to_string(lightIndex) + "].position", transf.position);
|
||||
shader.setVec3("lights[" + std::to_string(lightIndex) + "].color", l.color);
|
||||
shader.setFloat("lights[" + std::to_string(lightIndex) + "].intensity", l.intensity);
|
||||
shader.setMat4("lights[" + std::to_string(lightIndex) + "].lightSpace", l.lightSpace);
|
||||
shader.setInt("lights[" + std::to_string(lightIndex) + "].shadowMap", 10 + lightIndex);
|
||||
glActiveTexture(GL_TEXTURE10 + lightIndex);
|
||||
glBindTexture(GL_TEXTURE_2D, l.shadowMap);
|
||||
|
||||
++lightIndex;
|
||||
}
|
||||
}
|
||||
|
||||
void Renderer::UpdateView() {
|
||||
auto cam = m_registry.view<transform, camera>().back();
|
||||
auto camTransform = m_registry.get<transform>(cam);
|
||||
|
||||
m_view = glm::lookAt(
|
||||
camTransform.position,
|
||||
camTransform.position + camTransform.rotation,
|
||||
glm::vec3(0.f, 1.f, 0.f)
|
||||
);
|
||||
m_shader.setMat4("u_view", m_view);
|
||||
m_shader.setMat4("u_projection", m_proj);
|
||||
|
||||
m_shader.setVec3("viewPos", camTransform.position);
|
||||
}
|
||||
|
||||
void Renderer::RenderScene(Shader &shader) {
|
||||
std::unordered_map<unsigned int, std::vector<entt::entity>> batches;
|
||||
|
||||
for (auto [entt, item] : m_registry.view<batch::item>().each()) {
|
||||
if (batches.find(item.batchId) == batches.end())
|
||||
batches.insert(std::make_pair(item.batchId, std::vector<entt::entity>()));
|
||||
|
||||
batches[item.batchId].push_back(entt);
|
||||
}
|
||||
|
||||
shader.setBool("u_isInstanced", true);
|
||||
shader.setBool("isLight", false);
|
||||
shader.setVec3("currentLightColor", glm::vec3(0.f));
|
||||
for (auto [entt, b, m] : m_registry.view<batch, mesh>().each()) {
|
||||
// check if have items for batch render
|
||||
if (batches.find(b.id()) == batches.end()) continue;
|
||||
|
||||
auto &batchItems = batches[b.id()];
|
||||
|
||||
std::vector<glm::mat4> models;
|
||||
models.reserve(batchItems.size());
|
||||
|
||||
for (auto item : batchItems) {
|
||||
auto &t = m_registry.get<transform>(item);
|
||||
glm::mat4 rotation = glm::yawPitchRoll(t.rotation.y, t.rotation.x, t.rotation.z);
|
||||
auto itemModel = glm::translate(glm::mat4(1.f), t.position) * rotation;
|
||||
models.push_back(itemModel);
|
||||
}
|
||||
|
||||
auto prevInstanceVBO = b.m_instance_vbo;
|
||||
b.prepare(models.data(), models.size());
|
||||
if (prevInstanceVBO <= 0) {
|
||||
std::cout << "[DEBUG] enabling batch"<<std::endl;
|
||||
m.object->EnableBatch(b.m_instance_vbo);
|
||||
}
|
||||
m.object->Render(shader, batchItems.size());
|
||||
}
|
||||
shader.setBool("u_isInstanced", false);
|
||||
|
||||
for (auto [entity, transf, mesh] : m_registry.view<transform, mesh>(entt::exclude<batch, batch::item>).each()) {
|
||||
if (mesh.object == nullptr) {
|
||||
std::cerr << "WARN: Entity doesn't have a mesh to render" << std::endl;
|
||||
return;
|
||||
}
|
||||
|
||||
if (m_registry.all_of<light>(entity)) {
|
||||
auto &l = m_registry.get<light>(entity);
|
||||
shader.setBool("isLight", true);
|
||||
shader.setVec3("currentLightColor", l.color);
|
||||
} else {
|
||||
shader.setBool("isLight", false);
|
||||
shader.setVec3("currentLightColor", glm::vec3(0.f));
|
||||
}
|
||||
|
||||
glm::mat4 rotation = glm::yawPitchRoll(transf.rotation.y, transf.rotation.x, transf.rotation.z);
|
||||
m_model = glm::translate(glm::mat4(1.f), transf.position) * rotation;
|
||||
|
||||
shader.setMat4("u_model", m_model);
|
||||
|
||||
mesh.object->Render(shader, 1);
|
||||
}
|
||||
}
|
||||
|
||||
void Renderer::GenerateShadowMaps() {
|
||||
const unsigned int SHADOW_WIDTH = 1024, SHADOW_HEIGHT = 1024;
|
||||
|
||||
m_depthShader.use();
|
||||
|
||||
auto lights = m_registry.view<light>();
|
||||
|
||||
for (auto [lEntt, l] : lights.each()) {
|
||||
// TODO: support other light types when ready
|
||||
if (l.type != light::LightType::DIRECTIONAL) return;
|
||||
|
||||
glGenFramebuffers(1, &l.fbo);
|
||||
glGenTextures(1, &l.shadowMap);
|
||||
glBindTexture(GL_TEXTURE_2D, l.shadowMap);
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT24,
|
||||
SHADOW_WIDTH, SHADOW_HEIGHT, 0, GL_DEPTH_COMPONENT, GL_FLOAT, NULL);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
||||
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER);
|
||||
|
||||
float borderColor[] = {1.0f, 1.0f, 1.0f, 1.0f};
|
||||
glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, borderColor);
|
||||
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, l.fbo);
|
||||
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, l.shadowMap, 0);
|
||||
glDrawBuffer(GL_NONE);
|
||||
glReadBuffer(GL_NONE);
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
||||
}
|
||||
}
|
||||
|
||||
void Renderer::Render() {
|
||||
const unsigned int SHADOW_WIDTH = 1024, SHADOW_HEIGHT = 1024;
|
||||
|
||||
m_depthShader.use();
|
||||
|
||||
auto lights = m_registry.view<light, transform>();
|
||||
|
||||
for (auto [lEntt, l, t] : lights.each()) {
|
||||
// TODO: support other light types when ready
|
||||
if (l.type != light::LightType::DIRECTIONAL) return;
|
||||
|
||||
glClearColor(0x18/255.0f, 0x18/255.0f, 0x18/255.0f, 1.0f);
|
||||
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
||||
|
||||
float near_plane = 0.1f, far_plane = 50.0f;
|
||||
glm::vec3 target = glm::vec3(0.0f, 0.5f, 0.0f);
|
||||
glm::mat4 lightView = glm::lookAt(t.position, target, glm::vec3(0.0f, 1.0f, 0.0f));
|
||||
glm::mat4 lightProjection = glm::ortho(-6.0f, 6.0f, -6.0f, 6.0f, 1.0f, 20.0f);
|
||||
glm::mat4 lightSpaceMatrix = lightProjection * lightView;
|
||||
|
||||
m_depthShader.setMat4("u_lightSpace", lightSpaceMatrix);
|
||||
l.lightSpace = lightSpaceMatrix;
|
||||
|
||||
glCullFace(GL_FRONT);
|
||||
glViewport(0, 0, SHADOW_WIDTH, SHADOW_HEIGHT);
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, l.fbo);
|
||||
glClear(GL_DEPTH_BUFFER_BIT);
|
||||
RenderScene(m_depthShader);
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
||||
glCullFace(GL_BACK);
|
||||
}
|
||||
|
||||
// actual rendering
|
||||
|
||||
glViewport(0, 0, Window::GetWidth(), Window::GetHeight());
|
||||
|
||||
glClearColor(0x18/255.0f, 0x18/255.0f, 0x18/255.0f, 1);
|
||||
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
||||
|
||||
m_shader.use();
|
||||
|
||||
ApplyLights(m_shader);
|
||||
UpdateView();
|
||||
|
||||
RenderScene(m_shader);
|
||||
}
|
135
engine/src/renderer/shader.cpp
Normal file
135
engine/src/renderer/shader.cpp
Normal file
@ -0,0 +1,135 @@
|
||||
#include <iostream>
|
||||
#include <GL/glew.h>
|
||||
#include "engine/renderer/shader.h"
|
||||
|
||||
Shader::Shader()
|
||||
{
|
||||
}
|
||||
|
||||
Shader::~Shader()
|
||||
{
|
||||
}
|
||||
|
||||
void Shader::init(const std::string &vertexCode, const std::string &fragmentCode)
|
||||
{
|
||||
m_vertexCode = vertexCode;
|
||||
m_fragmentCode = fragmentCode;
|
||||
compile();
|
||||
link();
|
||||
}
|
||||
|
||||
void Shader::use()
|
||||
{
|
||||
glUseProgram(m_id);
|
||||
}
|
||||
|
||||
void Shader::setBool(const std::string &name, bool value) const
|
||||
{
|
||||
glUniform1i(glGetUniformLocation(m_id, name.c_str()), (int)value);
|
||||
}
|
||||
|
||||
void Shader::setInt(const std::string &name, int value) const
|
||||
{
|
||||
glUniform1i(glGetUniformLocation(m_id, name.c_str()), value);
|
||||
}
|
||||
|
||||
void Shader::setFloat(const std::string &name, float value) const
|
||||
{
|
||||
glUniform1f(glGetUniformLocation(m_id, name.c_str()), value);
|
||||
}
|
||||
|
||||
void Shader::setVec2(const std::string &name, const glm::vec2 &value) const
|
||||
{
|
||||
glUniform2fv(glGetUniformLocation(m_id, name.c_str()), 1, &value[0]);
|
||||
}
|
||||
void Shader::setVec2(const std::string &name, float x, float y) const
|
||||
{
|
||||
glUniform2f(glGetUniformLocation(m_id, name.c_str()), x, y);
|
||||
}
|
||||
|
||||
void Shader::setVec3(const std::string &name, const glm::vec3 &value) const
|
||||
{
|
||||
glUniform3fv(glGetUniformLocation(m_id, name.c_str()), 1, &value[0]);
|
||||
}
|
||||
void Shader::setVec3(const std::string &name, float x, float y, float z) const
|
||||
{
|
||||
glUniform3f(glGetUniformLocation(m_id, name.c_str()), x, y, z);
|
||||
}
|
||||
|
||||
void Shader::setVec4(const std::string &name, const glm::vec4 &value) const
|
||||
{
|
||||
glUniform4fv(glGetUniformLocation(m_id, name.c_str()), 1, &value[0]);
|
||||
}
|
||||
void Shader::setVec4(const std::string &name, float x, float y, float z, float w) const
|
||||
{
|
||||
glUniform4f(glGetUniformLocation(m_id, name.c_str()), x, y, z, w);
|
||||
}
|
||||
|
||||
void Shader::setMat2(const std::string &name, const glm::mat2 &mat) const
|
||||
{
|
||||
glUniformMatrix2fv(glGetUniformLocation(m_id, name.c_str()), 1, GL_FALSE, &mat[0][0]);
|
||||
}
|
||||
|
||||
void Shader::setMat3(const std::string &name, const glm::mat3 &mat) const
|
||||
{
|
||||
glUniformMatrix3fv(glGetUniformLocation(m_id, name.c_str()), 1, GL_FALSE, &mat[0][0]);
|
||||
}
|
||||
|
||||
void Shader::setMat4(const std::string &name, const glm::mat4 &mat) const
|
||||
{
|
||||
glUniformMatrix4fv(glGetUniformLocation(m_id, name.c_str()), 1, GL_FALSE, &mat[0][0]);
|
||||
}
|
||||
|
||||
void Shader::compile()
|
||||
{
|
||||
const char *vsCode = m_vertexCode.c_str();
|
||||
m_vertexId = glCreateShader(GL_VERTEX_SHADER);
|
||||
glShaderSource(m_vertexId, 1, &vsCode, NULL);
|
||||
glCompileShader(m_vertexId);
|
||||
checkCompileError(m_vertexId, "Vertex Shader");
|
||||
|
||||
const char *fsCode = m_fragmentCode.c_str();
|
||||
m_fragmentId = glCreateShader(GL_FRAGMENT_SHADER);
|
||||
glShaderSource(m_fragmentId, 1, &fsCode, NULL);
|
||||
glCompileShader(m_fragmentId);
|
||||
checkCompileError(m_fragmentId, "Fragment Shader");
|
||||
}
|
||||
|
||||
void Shader::link()
|
||||
{
|
||||
m_id = glCreateProgram();
|
||||
glAttachShader(m_id, m_vertexId);
|
||||
glAttachShader(m_id, m_fragmentId);
|
||||
glLinkProgram(m_id);
|
||||
checkLinkingError();
|
||||
glDeleteShader(m_vertexId);
|
||||
glDeleteShader(m_fragmentId);
|
||||
}
|
||||
|
||||
void Shader::checkCompileError(unsigned int shader, const std::string type)
|
||||
{
|
||||
int success;
|
||||
char infoLog[1024];
|
||||
glGetShaderiv(shader, GL_COMPILE_STATUS, &success);
|
||||
if (!success)
|
||||
{
|
||||
glGetShaderInfoLog(shader, 1024, NULL, infoLog);
|
||||
std::cout << "Shader: Error compiling " << type << ":" << std::endl
|
||||
<< infoLog
|
||||
<< std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
void Shader::checkLinkingError()
|
||||
{
|
||||
int success;
|
||||
char infoLog[1024];
|
||||
glGetProgramiv(m_id, GL_LINK_STATUS, &success);
|
||||
if (!success)
|
||||
{
|
||||
glGetProgramInfoLog(m_id, 1024, NULL, infoLog);
|
||||
std::cout << "Shader: Error linking shader program: " << std::endl
|
||||
<< infoLog
|
||||
<< std::endl;
|
||||
}
|
||||
}
|
36
engine/src/renderer/texture.cpp
Normal file
36
engine/src/renderer/texture.cpp
Normal file
@ -0,0 +1,36 @@
|
||||
#include <iostream>
|
||||
#include <memory>
|
||||
|
||||
#include <GL/glew.h>
|
||||
#include "engine/renderer/texture.h"
|
||||
|
||||
#define STB_IMAGE_IMPLEMENTATION
|
||||
#include "stb_image.h"
|
||||
|
||||
std::unique_ptr<Texture> Texture::LoadFile(const std::string& filename) {
|
||||
auto texture = std::make_unique<Texture>();
|
||||
|
||||
int w, h, c;
|
||||
unsigned char *data = stbi_load(filename.c_str(), &w, &h, &c, 4);
|
||||
if (!data) {
|
||||
std::cerr << "ERROR: Failed to load texture under '" << filename << "'" << std::endl;
|
||||
std::exit(1);
|
||||
}
|
||||
|
||||
glGenTextures(1, &texture.get()->m_id);
|
||||
glBindTexture(GL_TEXTURE_2D, texture.get()->m_id);
|
||||
|
||||
// TODO: configure properly
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, data);
|
||||
glGenerateMipmap(GL_TEXTURE_2D);
|
||||
|
||||
std::cout << "Loaded texture under '" << filename << "' with size of " << sizeof(data) << " bytes" << std::endl;
|
||||
stbi_image_free(data);
|
||||
|
||||
return std::move(texture);
|
||||
}
|
509
engine/src/renderer/wavefront.cpp
Normal file
509
engine/src/renderer/wavefront.cpp
Normal file
@ -0,0 +1,509 @@
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <cstring>
|
||||
#include <memory>
|
||||
#include <filesystem>
|
||||
#include <GL/glew.h>
|
||||
|
||||
#include "engine/IO/parser.h"
|
||||
#include "engine/renderer/mesh.h"
|
||||
#include "engine/renderer/wavefront.h"
|
||||
|
||||
#define DEFAULT_MATERIAL_NAME "default"
|
||||
|
||||
// ObjElement toElement(const std::string &s) {
|
||||
// if (s == "#") return ObjElement::OHASH;
|
||||
// if (s == "mtllib") return ObjElement::MTLLIB;
|
||||
// if (s == "usemtl") return ObjElement::USEMTL;
|
||||
// if (s == "o") return ObjElement::O;
|
||||
// if (s == "v") return ObjElement::V;
|
||||
// if (s == "vn") return ObjElement::VN;
|
||||
// if (s == "vt") return ObjElement::VT;
|
||||
// if (s == "f") return ObjElement::F;
|
||||
// return ObjElement::OUNKNOWN;
|
||||
// }
|
||||
|
||||
inline ObjElement toElement(const char* s) {
|
||||
switch (s[0]) {
|
||||
case '#': return ObjElement::OHASH;
|
||||
case 'm': if (strcmp(s, "mtllib") == 0) return ObjElement::MTLLIB; break;
|
||||
case 'u': if (strcmp(s, "usemtl") == 0) return ObjElement::USEMTL; break;
|
||||
case 'o': if (s[1] == '\0') return ObjElement::O; break;
|
||||
case 'v':
|
||||
if (s[1] == '\0') return ObjElement::V;
|
||||
if (s[1] == 'n' && s[2] == '\0') return ObjElement::VN;
|
||||
if (s[1] == 't' && s[2] == '\0') return ObjElement::VT;
|
||||
break;
|
||||
case 'f': if (s[1] == '\0') return ObjElement::F; break;
|
||||
}
|
||||
return ObjElement::OUNKNOWN;
|
||||
}
|
||||
|
||||
// MtlElement toMtlElement(const std::string &s) {
|
||||
// if (s == "#") return MtlElement::MHASH;
|
||||
// if (s == "newmtl") return MtlElement::NEWMTL;
|
||||
// if (s == "Ns") return MtlElement::NS;
|
||||
// if (s == "Ka") return MtlElement::KA;
|
||||
// if (s == "Ks") return MtlElement::KS;
|
||||
// if (s == "Kd") return MtlElement::KD;
|
||||
// if (s == "Ni") return MtlElement::NI;
|
||||
// if (s == "d") return MtlElement::D;
|
||||
// if (s == "illum") return MtlElement::ILLUM;
|
||||
// if (s == "map_Kd") return MtlElement::MAP_KD;
|
||||
// if (s == "map_Ka") return MtlElement::MAP_KA;
|
||||
// // if (s == "map_Ke") return MtlElement::MAP_KE;
|
||||
// return MtlElement::MUNKNOWN;
|
||||
// }
|
||||
|
||||
inline MtlElement toMtlElement(const char* s) {
|
||||
switch (s[0]) {
|
||||
case '#': return MtlElement::MHASH;
|
||||
case 'n':
|
||||
if (strcmp(s, "newmtl") == 0) return MtlElement::NEWMTL;
|
||||
break;
|
||||
case 'N':
|
||||
if (s[1] == 's' && s[2] == '\0') return MtlElement::NS;
|
||||
if (s[1] == 'i' && s[2] == '\0') return MtlElement::NI;
|
||||
break;
|
||||
case 'K':
|
||||
if (s[1] == 'a' && s[2] == '\0') return MtlElement::KA;
|
||||
if (s[1] == 's' && s[2] == '\0') return MtlElement::KS;
|
||||
if (s[1] == 'd' && s[2] == '\0') return MtlElement::KD;
|
||||
break;
|
||||
case 'd':
|
||||
if (s[1] == '\0') return MtlElement::D;
|
||||
break;
|
||||
case 'i':
|
||||
if (strcmp(s, "illum") == 0) return MtlElement::ILLUM;
|
||||
break;
|
||||
case 'm':
|
||||
if (strcmp(s, "map_Kd") == 0) return MtlElement::MAP_KD;
|
||||
if (strcmp(s, "map_Ka") == 0) return MtlElement::MAP_KA;
|
||||
// if (strcmp(s, "map_Ke") == 0) return MtlElement::MAP_KE;
|
||||
break;
|
||||
}
|
||||
return MtlElement::MUNKNOWN;
|
||||
}
|
||||
|
||||
inline int Object::NormalizeIndex(int idx, int baseCount) {
|
||||
// idx is the raw value returned by parser:
|
||||
// 0 -> means "not present" or invalid in our convention
|
||||
// >0 -> 1-based index -> convert to 0-based
|
||||
// <0 -> negative index -> relative to baseCount: baseCount + idx
|
||||
if (idx == 0) return -1; // absent / invalid
|
||||
if (idx > 0) return idx - 1; // 1-based -> 0-based
|
||||
return baseCount + idx; // negative -> count from end
|
||||
}
|
||||
|
||||
Object::Object() {
|
||||
m_vertices = std::vector<glm::vec3>();
|
||||
m_normals = std::vector<glm::vec3>();
|
||||
m_texCoords = std::vector<glm::vec2>();
|
||||
}
|
||||
|
||||
void Object::LoadMaterials(const std::filesystem::path& filename) {
|
||||
std::ifstream file(filename);
|
||||
if (!file.is_open()) {
|
||||
std::cerr << "Failed to open MTL file: " << filename << std::endl;
|
||||
return;
|
||||
}
|
||||
|
||||
std::string currentMaterialName;
|
||||
std::shared_ptr<Material> currentMaterial;
|
||||
|
||||
char line[1024]; // buffer per line
|
||||
|
||||
while (file.getline(line, sizeof(line))) {
|
||||
Parser p(line);
|
||||
char* prefix = p.TakeWord();
|
||||
if (!prefix) continue;
|
||||
|
||||
switch (toMtlElement(prefix)) {
|
||||
case MtlElement::MHASH: // comment
|
||||
continue;
|
||||
|
||||
case MtlElement::NEWMTL:
|
||||
{
|
||||
// If a material was being built, commit it first
|
||||
if (currentMaterial) {
|
||||
AddMaterial(currentMaterialName, std::move(currentMaterial));
|
||||
currentMaterial = nullptr;
|
||||
}
|
||||
|
||||
char* materialName = p.TakeWord();
|
||||
if (materialName) {
|
||||
currentMaterialName = materialName;
|
||||
currentMaterial = std::make_shared<Material>();
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case MtlElement::NS: // specular weight
|
||||
{
|
||||
float weight = p.TakeFloat();
|
||||
if (currentMaterial) currentMaterial->SetSpecularWeight(weight);
|
||||
break;
|
||||
}
|
||||
|
||||
case MtlElement::KA: // ambient color
|
||||
{
|
||||
float r = p.TakeFloat();
|
||||
float g = p.TakeFloat();
|
||||
float b = p.TakeFloat();
|
||||
if (currentMaterial) currentMaterial->SetAmbientColor(glm::vec3(r, g, b));
|
||||
break;
|
||||
}
|
||||
|
||||
case MtlElement::KS: // specular color
|
||||
{
|
||||
float r = p.TakeFloat();
|
||||
float g = p.TakeFloat();
|
||||
float b = p.TakeFloat();
|
||||
if (currentMaterial) currentMaterial->SetSpecularColor(glm::vec3(r, g, b));
|
||||
break;
|
||||
}
|
||||
|
||||
case MtlElement::KD: // diffuse color
|
||||
{
|
||||
float r = p.TakeFloat();
|
||||
float g = p.TakeFloat();
|
||||
float b = p.TakeFloat();
|
||||
if (currentMaterial) currentMaterial->SetDiffuseColor(glm::vec3(r, g, b));
|
||||
break;
|
||||
}
|
||||
|
||||
case MtlElement::D: // opacity
|
||||
{
|
||||
float d = p.TakeFloat();
|
||||
if (currentMaterial) currentMaterial->SetOpacity(d);
|
||||
break;
|
||||
}
|
||||
|
||||
case MtlElement::ILLUM: // illumination model
|
||||
{
|
||||
int illum = p.TakeInt();
|
||||
if (currentMaterial) currentMaterial->SetIllumination(illum);
|
||||
break;
|
||||
}
|
||||
|
||||
case MtlElement::MAP_KD: // diffuse texture map
|
||||
{
|
||||
// take rest of line as texture path (can contain spaces)
|
||||
char* texPath = p.TakeUntil('\0');
|
||||
if (texPath && currentMaterial) {
|
||||
// trim trailing spaces
|
||||
size_t len = std::strlen(texPath);
|
||||
while (len > 0 && (texPath[len - 1] == ' ' || texPath[len - 1] == '\t'))
|
||||
texPath[--len] = '\0';
|
||||
|
||||
currentMaterial->SetDiffuseTexture(Texture::LoadFile(texPath));
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case MtlElement::MAP_KA: // ambient texture map
|
||||
{
|
||||
char* texPath = p.TakeUntil('\0');
|
||||
if (texPath && currentMaterial) {
|
||||
size_t len = std::strlen(texPath);
|
||||
while (len > 0 && (texPath[len - 1] == ' ' || texPath[len - 1] == '\t'))
|
||||
texPath[--len] = '\0';
|
||||
|
||||
// optional: handle ambient texture
|
||||
// currentMaterial->SetAmbientTexture(Texture::LoadFile(texPath));
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
// ignore unknown tokens
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Commit last material if pending
|
||||
if (currentMaterial) {
|
||||
AddMaterial(currentMaterialName, std::move(currentMaterial));
|
||||
}
|
||||
|
||||
file.close();
|
||||
}
|
||||
|
||||
void Object::AddMaterial(std::string name, std::shared_ptr<Material> material)
|
||||
{
|
||||
m_materials.insert(std::make_pair(std::move(name), std::move(material)));
|
||||
}
|
||||
|
||||
std::shared_ptr<Material> Object::GetMaterial(std::string name)
|
||||
{
|
||||
auto material = m_materials.find(name);
|
||||
if (material == m_materials.end()) return nullptr;
|
||||
return material->second;
|
||||
}
|
||||
|
||||
void Object::CreateNewMesh(const std::string& materialName)
|
||||
{
|
||||
Mesh mesh;
|
||||
mesh.materialName = materialName;
|
||||
m_meshes.push_back(mesh);
|
||||
}
|
||||
|
||||
Mesh& Object::GetLastMesh()
|
||||
{
|
||||
if (m_meshes.empty()) {
|
||||
auto material = std::make_shared<Material>();
|
||||
material->SetAmbientColor(glm::vec3(0.52f, 0.52f, 0.52f));
|
||||
AddMaterial(DEFAULT_MATERIAL_NAME, std::move(material));
|
||||
CreateNewMesh(DEFAULT_MATERIAL_NAME);
|
||||
}
|
||||
return m_meshes.back();
|
||||
}
|
||||
|
||||
Object* Object::LoadFile(const std::string& filename) {
|
||||
std::ifstream file(filename);
|
||||
if (!file.is_open()) {
|
||||
std::cerr << "Failed to open OBJ file: " << filename << std::endl;
|
||||
return {};
|
||||
}
|
||||
|
||||
Object* obj = new Object();
|
||||
char line[1024]; // static buffer for each line (enough for OBJ lines)
|
||||
|
||||
while (file.getline(line, sizeof(line))) {
|
||||
Parser p(line);
|
||||
char* prefix = p.TakeWord();
|
||||
if (!prefix) continue;
|
||||
|
||||
switch (toElement(prefix)) {
|
||||
case ObjElement::OHASH: // comment
|
||||
continue;
|
||||
|
||||
case ObjElement::MTLLIB:
|
||||
{
|
||||
char* mtlFile = p.TakeWord();
|
||||
if (mtlFile) {
|
||||
std::filesystem::path fullPath = filename;
|
||||
std::filesystem::path mtlPath = fullPath.replace_filename(mtlFile);
|
||||
obj->LoadMaterials(mtlPath);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case ObjElement::USEMTL:
|
||||
{
|
||||
char* materialName = p.TakeWord();
|
||||
if (materialName) {
|
||||
auto& mesh = obj->GetLastMesh();
|
||||
if (mesh.materialName != materialName) {
|
||||
Mesh newMesh;
|
||||
newMesh.materialName = materialName;
|
||||
obj->m_meshes.push_back(newMesh);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case ObjElement::O: // object name
|
||||
{
|
||||
char* name = p.TakeWord();
|
||||
if (name) obj->m_name = name;
|
||||
break;
|
||||
}
|
||||
|
||||
case ObjElement::V: // vertex
|
||||
{
|
||||
float x = p.TakeFloat();
|
||||
float y = p.TakeFloat();
|
||||
float z = p.TakeFloat();
|
||||
float w = p.TakeFloat();
|
||||
|
||||
if (w != 0.0f && w != 1.0f) {
|
||||
x /= w; y /= w; z /= w;
|
||||
}
|
||||
obj->m_vertices.emplace_back(x, y, z);
|
||||
break;
|
||||
}
|
||||
|
||||
case ObjElement::VN: // normal
|
||||
{
|
||||
float x = p.TakeFloat();
|
||||
float y = p.TakeFloat();
|
||||
float z = p.TakeFloat();
|
||||
obj->m_normals.emplace_back(x, y, z);
|
||||
break;
|
||||
}
|
||||
|
||||
case ObjElement::VT: // texcoord
|
||||
{
|
||||
float u = p.TakeFloat();
|
||||
float v = p.TakeFloat();
|
||||
obj->m_texCoords.emplace_back(u, 1.0f - v);
|
||||
break;
|
||||
}
|
||||
|
||||
case ObjElement::F: // face
|
||||
{
|
||||
auto& mesh = obj->GetLastMesh();
|
||||
int raw_vi, raw_ti, raw_ni;
|
||||
|
||||
while (p.TakeFaceIndices(raw_vi, raw_ti, raw_ni)) {
|
||||
// Convert raw OBJ indices to 0-based / -1 sentinel
|
||||
int vi = Object::NormalizeIndex(raw_vi, (int)obj->m_vertices.size());
|
||||
int ti = Object::NormalizeIndex(raw_ti, (int)obj->m_texCoords.size());
|
||||
int ni = Object::NormalizeIndex(raw_ni, (int)obj->m_normals.size());
|
||||
|
||||
if (vi < 0) {
|
||||
// malformed token (no vertex) — skip
|
||||
continue;
|
||||
}
|
||||
|
||||
glm::vec3 vert = obj->m_vertices[vi];
|
||||
glm::vec3 norm(0.0f);
|
||||
glm::vec2 texCoord(0.0f);
|
||||
|
||||
if (ni >= 0) norm = obj->m_normals[ni];
|
||||
if (ti >= 0) texCoord = obj->m_texCoords[ti];
|
||||
|
||||
mesh.m_vertexBuffer.emplace_back(vert, norm, texCoord);
|
||||
mesh.m_indexBuffer.push_back(mesh.m_vertexBuffer.size() - 1);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
// ignore unknown tokens
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
std::cout << "Object name: " << obj->m_name << std::endl;
|
||||
std::cout << "Vertices count: " << obj->m_vertices.size() << std::endl;
|
||||
std::cout << "Normals count: " << obj->m_normals.size() << std::endl;
|
||||
std::cout << "TexCoords count: " << obj->m_texCoords.size() << std::endl;
|
||||
std::cout << "Meshes count: " << obj->m_meshes.size() << std::endl;
|
||||
std::cout << "Materials count: " << obj->m_materials.size() << std::endl;
|
||||
|
||||
file.close();
|
||||
|
||||
for (auto &mesh : obj->m_meshes) {
|
||||
mesh.Upload();
|
||||
}
|
||||
|
||||
return obj;
|
||||
}
|
||||
|
||||
void Object::EnableBatch(unsigned int instanceVBO) {
|
||||
for (auto &mesh : m_meshes) {
|
||||
mesh.Bind();
|
||||
|
||||
glBindBuffer(GL_ARRAY_BUFFER, instanceVBO);
|
||||
std::size_t vec4Size = sizeof(glm::vec4);
|
||||
for (int i = 0; i < 4; ++i) {
|
||||
glEnableVertexAttribArray(3 + i); // use locations 3,4,5,6 for instance matrix
|
||||
glVertexAttribPointer(3 + i, 4, GL_FLOAT, GL_FALSE,
|
||||
sizeof(glm::mat4), (void*)(i * vec4Size));
|
||||
glVertexAttribDivisor(3 + i, 1); // IMPORTANT: one per instance, not per vertex
|
||||
}
|
||||
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
||||
|
||||
mesh.Unbind();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// void Object::Render(Shader& shader)
|
||||
// {
|
||||
// for (auto &mesh : m_meshes) {
|
||||
// auto material = GetMaterial(mesh.materialName);
|
||||
|
||||
// shader.setFloat("ambientStrength", 0.2f);
|
||||
// shader.setFloat("shininess", material->GetSpecularWeight());
|
||||
// shader.setFloat("opacity", material->GetOpacity());
|
||||
// shader.setBool("useSpecular", material->GetIllumination() >= 2);
|
||||
// shader.setFloat("specularStrength", 1.0f);
|
||||
// shader.setVec3("ambientColor", material->GetAmbientColor());
|
||||
// shader.setVec3("diffuseColor", material->GetDiffuseColor());
|
||||
// shader.setVec3("specularColor", material->GetSpecularColor());
|
||||
|
||||
// if (material->HasDiffuseTexture()) {
|
||||
// shader.setBool("useTexture", true);
|
||||
// glActiveTexture(GL_TEXTURE0);
|
||||
// glBindTexture(GL_TEXTURE_2D, material->GetDiffuseTexture()->GetID());
|
||||
// shader.setInt("diffuseTex", 0);
|
||||
// } else {
|
||||
// shader.setBool("useTexture", false);
|
||||
// }
|
||||
|
||||
// mesh.Render();
|
||||
// }
|
||||
// }
|
||||
|
||||
void Object::Render(Shader& shader, unsigned int count)
|
||||
{
|
||||
for (auto &mesh : m_meshes)
|
||||
{
|
||||
auto material = GetMaterial(mesh.materialName);
|
||||
|
||||
// --- Basic material properties ---
|
||||
shader.setFloat("opacity", material->GetOpacity());
|
||||
|
||||
// Albedo (base color)
|
||||
shader.setVec3("albedo", material->GetDiffuseColor());
|
||||
|
||||
// Metallic and roughness (defaults)
|
||||
shader.setFloat("metallic", 0.8f);
|
||||
shader.setFloat("roughness", 0.5f);
|
||||
shader.setFloat("ao", 1.0f); // default ambient occlusion if none
|
||||
|
||||
// --- Optional textures ---
|
||||
int texUnit = 0;
|
||||
|
||||
// Albedo texture
|
||||
if (material->HasDiffuseTexture()) {
|
||||
shader.setBool("useAlbedoMap", true);
|
||||
glActiveTexture(GL_TEXTURE0 + texUnit);
|
||||
glBindTexture(GL_TEXTURE_2D, material->GetDiffuseTexture()->GetID());
|
||||
shader.setInt("albedoTex", texUnit++);
|
||||
} else {
|
||||
shader.setBool("useAlbedoMap", false);
|
||||
}
|
||||
|
||||
// Metallic texture
|
||||
// if (material->HasMetallicTexture()) {
|
||||
if (false) {
|
||||
shader.setBool("useMetallicMap", true);
|
||||
glActiveTexture(GL_TEXTURE0 + texUnit);
|
||||
// glBindTexture(GL_TEXTURE_2D, material->GetMetallicTexture()->GetID());
|
||||
shader.setInt("metallicTex", texUnit++);
|
||||
} else {
|
||||
shader.setBool("useMetallicMap", false);
|
||||
}
|
||||
|
||||
// Roughness texture
|
||||
// if (material->HasRoughnessTexture()) {
|
||||
if (false) {
|
||||
shader.setBool("useRoughnessMap", true);
|
||||
glActiveTexture(GL_TEXTURE0 + texUnit);
|
||||
// glBindTexture(GL_TEXTURE_2D, material->GetRoughnessTexture()->GetID());
|
||||
shader.setInt("roughnessTex", texUnit++);
|
||||
} else {
|
||||
shader.setBool("useRoughnessMap", false);
|
||||
}
|
||||
|
||||
// AO texture
|
||||
// if (material->HasAoTexture()) {
|
||||
if (false) {
|
||||
shader.setBool("useAoMap", true);
|
||||
glActiveTexture(GL_TEXTURE0 + texUnit);
|
||||
// glBindTexture(GL_TEXTURE_2D, material->GetAoTexture()->GetID());
|
||||
shader.setInt("aoTex", texUnit++);
|
||||
} else {
|
||||
shader.setBool("useAoMap", false);
|
||||
}
|
||||
|
||||
// --- Render mesh ---
|
||||
mesh.Render(count);
|
||||
}
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user