Remade everything again.
Added 3d OpenGL baced rendere instead of 2D rendering
This commit is contained in:
parent
5657cf318d
commit
d81fa19bc4
28
Makefile
28
Makefile
@ -6,34 +6,43 @@ CXXFLAGS := -Wall -Wextra -std=c++17
|
||||
|
||||
# Directories
|
||||
SRC_DIR := src
|
||||
VENDOR_DIRS := vendor/imgui-docking vendor/stb # Removed vendor/glad
|
||||
VENDOR_DIRS := vendor/imgui-docking vendor/stb
|
||||
BUILD_DIR := build
|
||||
|
||||
# Include Directories
|
||||
# Add GLFW include paths
|
||||
GLFW_INCLUDE := C:/libraries/glfw/include
|
||||
INCLUDE_DIRS := $(SRC_DIR) $(VENDOR_DIRS) $(GLFW_INCLUDE) vendor/stb/include # Removed vendor/glad/include
|
||||
INCLUDE_DIRS := $(SRC_DIR) $(VENDOR_DIRS) $(GLFW_INCLUDE) vendor/stb/include
|
||||
INCLUDES := $(addprefix -I, $(INCLUDE_DIRS))
|
||||
|
||||
# Update compiler flags with include paths
|
||||
CXXFLAGS += $(INCLUDES)
|
||||
|
||||
# -------------------------------------------------------------------------
|
||||
# Source Files
|
||||
SRC_FILES := $(wildcard $(SRC_DIR)/*.cpp)
|
||||
# 1) Recursively gather *.cpp in src (including subfolders).
|
||||
# 2) Gather *.cpp from vendor/imgui-docking, vendor/stb, etc.
|
||||
# -------------------------------------------------------------------------
|
||||
SRC_FILES := $(wildcard $(SRC_DIR)/*.cpp) \
|
||||
$(wildcard $(SRC_DIR)/**/*.cpp)
|
||||
|
||||
VENDOR_SRC := $(foreach dir, $(VENDOR_DIRS), $(wildcard $(dir)/*.cpp))
|
||||
STB_SRC := $(wildcard vendor/stb/src/*.cpp) # If stb has .cpp files
|
||||
ALL_SRC := $(SRC_FILES) $(VENDOR_SRC) $(STB_SRC)
|
||||
|
||||
# -------------------------------------------------------------------------
|
||||
# Object Files
|
||||
# Convert each .cpp to a corresponding .o under the build/ directory.
|
||||
# For example:
|
||||
# src/Engine.cpp -> build/src/Engine.o
|
||||
# src/Windows/LoggerWindow.cpp -> build/src/Windows/LoggerWindow.o
|
||||
# -------------------------------------------------------------------------
|
||||
OBJ_FILES := $(patsubst %.cpp, $(BUILD_DIR)/%.o, $(ALL_SRC))
|
||||
# Removed GLAD object files
|
||||
# OBJ_FILES += $(patsubst %.c, $(BUILD_DIR)/%.o, $(GLAD_SRC)) # Removed
|
||||
|
||||
# Target executable name
|
||||
TARGET := TesseractEngine.exe
|
||||
|
||||
# Libraries
|
||||
LIBS := -LC:/libraries/glfw/lib -lglfw3 -lopengl32 -lgdi32 -limm32 -lole32 -loleaut32 -luuid -lwinmm
|
||||
LIBS := -LC:/libraries/glfw/lib -lglfw3 -lopengl32 -lgdi32 -limm32 -lole32 -loleaut32 -luuid -lwinmm -lglew32 -lglu32
|
||||
|
||||
# Phony Targets
|
||||
.PHONY: all clean copy_assets
|
||||
@ -52,6 +61,7 @@ $(TARGET): $(OBJ_FILES)
|
||||
$(CXX) $(CXXFLAGS) -o $@ $^ $(LIBS)
|
||||
|
||||
# Pattern rule to compile .cpp files to .o files
|
||||
# Note the mkdir on the $(dir $@) ensures subfolders under build/ exist.
|
||||
$(BUILD_DIR)/%.o: %.cpp
|
||||
@mkdir "$(dir $@)" >nul 2>&1 || echo Directory exists
|
||||
@echo Compiling $<...
|
||||
@ -60,5 +70,5 @@ $(BUILD_DIR)/%.o: %.cpp
|
||||
# Clean build artifacts
|
||||
clean:
|
||||
@echo Cleaning up...
|
||||
rmdir /s /q "$(BUILD_DIR)"
|
||||
del /q "$(TARGET)"
|
||||
if exist "$(BUILD_DIR)" rmdir /s /q "$(BUILD_DIR)"
|
||||
if exist "$(TARGET)" del /q "$(TARGET)"
|
||||
|
18
shaders/UnlitMaterial.frag
Normal file
18
shaders/UnlitMaterial.frag
Normal file
@ -0,0 +1,18 @@
|
||||
#version 330 core
|
||||
|
||||
in vec2 vUV; // UV from vertex shader
|
||||
out vec4 FragColor; // Final color output
|
||||
|
||||
uniform vec4 uColor; // A user-set solid color
|
||||
uniform sampler2D uTexture; // Optional texture
|
||||
|
||||
void main()
|
||||
{
|
||||
// Sample the texture. If you don't want texturing, remove this.
|
||||
vec4 texColor = texture(uTexture, vUV);
|
||||
|
||||
// Multiply the texture by our uniform color.
|
||||
// If you want a pure color (no texture), just do:
|
||||
// FragColor = uColor;
|
||||
FragColor = texColor * uColor;
|
||||
}
|
14
shaders/UnlitMaterial.vert
Normal file
14
shaders/UnlitMaterial.vert
Normal file
@ -0,0 +1,14 @@
|
||||
#version 330 core
|
||||
|
||||
layout(location = 0) in vec3 aPos; // Vertex position
|
||||
layout(location = 1) in vec2 aUV; // Texture UV coordinate (optional)
|
||||
|
||||
uniform mat4 uMVP; // Combined Model-View-Projection matrix
|
||||
|
||||
out vec2 vUV; // Pass UV to the fragment shader
|
||||
|
||||
void main()
|
||||
{
|
||||
vUV = aUV;
|
||||
gl_Position = uMVP * vec4(aPos, 1.0);
|
||||
}
|
@ -1,45 +0,0 @@
|
||||
#version 330 core
|
||||
out vec4 FragColor;
|
||||
|
||||
in vec3 FragPos;
|
||||
in vec3 Normal;
|
||||
in vec2 TexCoords;
|
||||
|
||||
struct Material {
|
||||
sampler2D diffuse;
|
||||
sampler2D specular;
|
||||
float shininess;
|
||||
};
|
||||
|
||||
struct Light {
|
||||
vec3 position;
|
||||
|
||||
vec3 ambient;
|
||||
vec3 diffuse;
|
||||
vec3 specular;
|
||||
};
|
||||
|
||||
uniform Light light;
|
||||
uniform Material material;
|
||||
uniform vec3 viewPos;
|
||||
|
||||
void main()
|
||||
{
|
||||
// Ambient
|
||||
vec3 ambient = light.ambient * texture(material.diffuse, TexCoords).rgb;
|
||||
|
||||
// Diffuse
|
||||
vec3 norm = normalize(Normal);
|
||||
vec3 lightDir = normalize(light.position - FragPos);
|
||||
float diff = max(dot(norm, lightDir), 0.0);
|
||||
vec3 diffuse = light.diffuse * diff * texture(material.diffuse, TexCoords).rgb;
|
||||
|
||||
// Specular
|
||||
vec3 viewDir = normalize(viewPos - FragPos);
|
||||
vec3 reflectDir = reflect(-lightDir, norm);
|
||||
float spec = pow(max(dot(viewDir, reflectDir), 0.0), material.shininess);
|
||||
vec3 specular = light.specular * spec * texture(material.specular, TexCoords).rgb;
|
||||
|
||||
vec3 result = ambient + diffuse + specular;
|
||||
FragColor = vec4(result, 1.0);
|
||||
}
|
@ -1,21 +0,0 @@
|
||||
#version 330 core
|
||||
layout (location = 0) in vec3 aPos;
|
||||
layout (location = 1) in vec3 aNormal;
|
||||
layout (location = 2) in vec2 aTexCoords;
|
||||
|
||||
out vec3 FragPos;
|
||||
out vec3 Normal;
|
||||
out vec2 TexCoords;
|
||||
|
||||
uniform mat4 model;
|
||||
uniform mat4 view;
|
||||
uniform mat4 projection;
|
||||
|
||||
void main()
|
||||
{
|
||||
FragPos = vec3(model * vec4(aPos, 1.0));
|
||||
Normal = mat3(transpose(inverse(model))) * aNormal;
|
||||
TexCoords = aTexCoords;
|
||||
|
||||
gl_Position = projection * view * vec4(FragPos, 1.0);
|
||||
}
|
@ -1,108 +0,0 @@
|
||||
// src/CameraComponent.h
|
||||
#pragma once
|
||||
|
||||
#include <glm/glm.hpp>
|
||||
#include <glm/gtc/matrix_transform.hpp>
|
||||
|
||||
struct CameraComponent {
|
||||
glm::vec3 Position;
|
||||
glm::vec3 Front;
|
||||
glm::vec3 Up;
|
||||
glm::vec3 Right;
|
||||
glm::vec3 WorldUp;
|
||||
|
||||
// Euler Angles
|
||||
float Yaw;
|
||||
float Pitch;
|
||||
|
||||
// Camera options
|
||||
float MovementSpeed;
|
||||
float MouseSensitivity;
|
||||
float Zoom;
|
||||
|
||||
CameraComponent(
|
||||
glm::vec3 position = glm::vec3(0.0f, 0.0f, 3.0f),
|
||||
glm::vec3 up = glm::vec3(0.0f, 1.0f, 0.0f),
|
||||
float yaw = -90.0f,
|
||||
float pitch = 0.0f
|
||||
) : Front(glm::vec3(0.0f, 0.0f, -1.0f)),
|
||||
MovementSpeed(2.5f),
|
||||
MouseSensitivity(0.1f),
|
||||
Zoom(45.0f)
|
||||
{
|
||||
Position = position;
|
||||
WorldUp = up;
|
||||
Yaw = yaw;
|
||||
Pitch = pitch;
|
||||
// Calculate the initial Front, Right, and Up vectors
|
||||
glm::vec3 front;
|
||||
front.x = cos(glm::radians(Yaw)) * cos(glm::radians(Pitch));
|
||||
front.y = sin(glm::radians(Pitch));
|
||||
front.z = sin(glm::radians(Yaw)) * cos(glm::radians(Pitch));
|
||||
Front = glm::normalize(front);
|
||||
Right = glm::normalize(glm::cross(Front, WorldUp));
|
||||
Up = glm::normalize(glm::cross(Right, Front));
|
||||
}
|
||||
|
||||
// Returns the view matrix calculated using Euler Angles and the LookAt Matrix
|
||||
glm::mat4 GetViewMatrix()
|
||||
{
|
||||
return glm::lookAt(Position, Position + Front, Up);
|
||||
}
|
||||
|
||||
// Processes input received from any keyboard-like input system.
|
||||
void ProcessKeyboard(int direction, float deltaTime)
|
||||
{
|
||||
float velocity = MovementSpeed * deltaTime;
|
||||
if (direction == 0) // Forward
|
||||
Position += Front * velocity;
|
||||
if (direction == 1) // Backward
|
||||
Position -= Front * velocity;
|
||||
if (direction == 2) // Left
|
||||
Position -= Right * velocity;
|
||||
if (direction == 3) // Right
|
||||
Position += Right * velocity;
|
||||
if (direction == 4) // Up
|
||||
Position += Up * velocity;
|
||||
if (direction == 5) // Down
|
||||
Position -= Up * velocity;
|
||||
}
|
||||
|
||||
// Processes input received from a mouse input system.
|
||||
void ProcessMouseMovement(float xoffset, float yoffset, bool constrainPitch = true)
|
||||
{
|
||||
xoffset *= MouseSensitivity;
|
||||
yoffset *= MouseSensitivity;
|
||||
|
||||
Yaw += xoffset;
|
||||
Pitch += yoffset;
|
||||
|
||||
// Make sure that when pitch is out of bounds, screen doesn't get flipped
|
||||
if(constrainPitch)
|
||||
{
|
||||
if(Pitch > 89.0f)
|
||||
Pitch = 89.0f;
|
||||
if(Pitch < -89.0f)
|
||||
Pitch = -89.0f;
|
||||
}
|
||||
|
||||
// Update Front, Right and Up Vectors using the updated Euler angles
|
||||
glm::vec3 front;
|
||||
front.x = cos(glm::radians(Yaw)) * cos(glm::radians(Pitch));
|
||||
front.y = sin(glm::radians(Pitch));
|
||||
front.z = sin(glm::radians(Yaw)) * cos(glm::radians(Pitch));
|
||||
Front = glm::normalize(front);
|
||||
Right = glm::normalize(glm::cross(Front, WorldUp));
|
||||
Up = glm::normalize(glm::cross(Right, Front));
|
||||
}
|
||||
|
||||
// Processes input received from a mouse scroll-wheel event.
|
||||
void ProcessMouseScroll(float yoffset)
|
||||
{
|
||||
Zoom -= yoffset;
|
||||
if(Zoom < 1.0f)
|
||||
Zoom = 1.0f;
|
||||
if(Zoom > 45.0f)
|
||||
Zoom = 45.0f;
|
||||
}
|
||||
};
|
@ -1,40 +0,0 @@
|
||||
// src/CameraSystem.h
|
||||
#pragma once
|
||||
|
||||
#include "ECS.h"
|
||||
#include "CameraComponent.h"
|
||||
#include <GLFW/glfw3.h>
|
||||
#include <glm/glm.hpp>
|
||||
|
||||
class CameraSystem {
|
||||
public:
|
||||
CameraSystem(GLFWwindow* window, float deltaTime)
|
||||
: window(window), deltaTime(deltaTime) {}
|
||||
|
||||
void ProcessInput(EntityManager& em, ComponentManager& cm) {
|
||||
// Iterate through entities with CameraComponent
|
||||
const auto& entities = em.GetActiveEntities();
|
||||
for(auto entity : entities) {
|
||||
if(cm.HasComponent<CameraComponent>(entity)) {
|
||||
auto& camera = cm.GetComponent<CameraComponent>(entity);
|
||||
// Implement camera movement based on input
|
||||
if(glfwGetKey(window, GLFW_KEY_W) == GLFW_PRESS)
|
||||
camera.ProcessKeyboard(0, deltaTime); // Forward
|
||||
if(glfwGetKey(window, GLFW_KEY_S) == GLFW_PRESS)
|
||||
camera.ProcessKeyboard(1, deltaTime); // Backward
|
||||
if(glfwGetKey(window, GLFW_KEY_A) == GLFW_PRESS)
|
||||
camera.ProcessKeyboard(2, deltaTime); // Left
|
||||
if(glfwGetKey(window, GLFW_KEY_D) == GLFW_PRESS)
|
||||
camera.ProcessKeyboard(3, deltaTime); // Right
|
||||
if(glfwGetKey(window, GLFW_KEY_SPACE) == GLFW_PRESS)
|
||||
camera.ProcessKeyboard(4, deltaTime); // Up
|
||||
if(glfwGetKey(window, GLFW_KEY_LEFT_SHIFT) == GLFW_PRESS)
|
||||
camera.ProcessKeyboard(5, deltaTime); // Down
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
GLFWwindow* window;
|
||||
float deltaTime;
|
||||
};
|
@ -1,21 +0,0 @@
|
||||
// Components.h
|
||||
#pragma once
|
||||
#include <string>
|
||||
#include <glm/glm.hpp> // Ensure you have GLM installed and linked
|
||||
|
||||
struct TransformComponent {
|
||||
glm::vec3 position;
|
||||
glm::vec3 rotation;
|
||||
glm::vec3 scale;
|
||||
|
||||
TransformComponent()
|
||||
: position(0.0f), rotation(0.0f), scale(1.0f) {}
|
||||
};
|
||||
|
||||
struct SpriteComponent {
|
||||
std::string texturePath;
|
||||
// Add more sprite-related properties here
|
||||
|
||||
SpriteComponent(const std::string& path = "")
|
||||
: texturePath(path) {}
|
||||
};
|
204
src/ECS.h
204
src/ECS.h
@ -1,204 +0,0 @@
|
||||
// src/ECS.h
|
||||
#pragma once
|
||||
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
#include <typeindex>
|
||||
#include <typeinfo>
|
||||
#include <memory>
|
||||
#include <algorithm>
|
||||
#include <string>
|
||||
#include <stdexcept> // Added to fix 'runtime_error' errors
|
||||
|
||||
// Forward declaration
|
||||
class ComponentManager;
|
||||
|
||||
// Type alias for Entity
|
||||
using Entity = uint32_t;
|
||||
const Entity MAX_ENTITIES = 5000;
|
||||
|
||||
// Simple Vector3 struct to replace glm::vec3
|
||||
struct Vector3 {
|
||||
float x, y, z;
|
||||
|
||||
Vector3(float x_=0.0f, float y_=0.0f, float z_=0.0f)
|
||||
: x(x_), y(y_), z(z_) {}
|
||||
};
|
||||
|
||||
// =====================
|
||||
// Components
|
||||
// =====================
|
||||
|
||||
struct TransformComponent {
|
||||
Vector3 position;
|
||||
Vector3 rotation;
|
||||
Vector3 scale;
|
||||
|
||||
TransformComponent()
|
||||
: position(0.0f, 0.0f, 0.0f),
|
||||
rotation(0.0f, 0.0f, 0.0f),
|
||||
scale(1.0f, 1.0f, 1.0f) {}
|
||||
};
|
||||
|
||||
struct SpriteComponent {
|
||||
std::string texturePath;
|
||||
// Add more sprite-related properties here
|
||||
|
||||
SpriteComponent(const std::string& path = "")
|
||||
: texturePath(path) {}
|
||||
};
|
||||
|
||||
// =====================
|
||||
// ECS Core Classes
|
||||
// =====================
|
||||
|
||||
// Base class for Component Arrays
|
||||
class IComponentArray {
|
||||
public:
|
||||
virtual ~IComponentArray() = default;
|
||||
virtual void EntityDestroyed(Entity entity) = 0;
|
||||
};
|
||||
|
||||
// Template class for storing components of type T
|
||||
template<typename T>
|
||||
class ComponentArray : public IComponentArray {
|
||||
public:
|
||||
void InsertData(Entity entity, T component) {
|
||||
if (entityToIndex.find(entity) != entityToIndex.end())
|
||||
return; // Component already exists for this entity
|
||||
size_t newIndex = components.size();
|
||||
entityToIndex[entity] = newIndex;
|
||||
indexToEntity[newIndex] = entity;
|
||||
components.emplace_back(component);
|
||||
}
|
||||
|
||||
void RemoveData(Entity entity) {
|
||||
auto it = entityToIndex.find(entity);
|
||||
if (it == entityToIndex.end())
|
||||
return; // Component does not exist
|
||||
|
||||
size_t index = it->second;
|
||||
size_t lastIndex = components.size() - 1;
|
||||
components[index] = components[lastIndex];
|
||||
|
||||
Entity lastEntity = indexToEntity[lastIndex];
|
||||
entityToIndex[lastEntity] = index;
|
||||
indexToEntity[index] = lastEntity;
|
||||
|
||||
components.pop_back();
|
||||
entityToIndex.erase(entity);
|
||||
indexToEntity.erase(lastIndex);
|
||||
}
|
||||
|
||||
bool HasData(Entity entity) const {
|
||||
return entityToIndex.find(entity) != entityToIndex.end();
|
||||
}
|
||||
|
||||
T& GetData(Entity entity) {
|
||||
return components.at(entityToIndex.at(entity));
|
||||
}
|
||||
|
||||
void EntityDestroyed(Entity entity) override {
|
||||
if (entityToIndex.find(entity) != entityToIndex.end()) {
|
||||
RemoveData(entity);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
std::vector<T> components;
|
||||
std::unordered_map<Entity, size_t> entityToIndex;
|
||||
std::unordered_map<size_t, Entity> indexToEntity;
|
||||
};
|
||||
|
||||
// ComponentManager handles all components
|
||||
class ComponentManager {
|
||||
public:
|
||||
template<typename T>
|
||||
void RegisterComponent() {
|
||||
const std::type_index typeName = typeid(T);
|
||||
if (componentArrays.find(typeName) != componentArrays.end()) {
|
||||
// Component already registered
|
||||
return;
|
||||
}
|
||||
componentArrays[typeName] = std::make_shared<ComponentArray<T>>();
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void AddComponent(Entity entity, T component) {
|
||||
GetComponentArray<T>()->InsertData(entity, component);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void RemoveComponent(Entity entity) {
|
||||
GetComponentArray<T>()->RemoveData(entity);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
bool HasComponent(Entity entity) const {
|
||||
return GetComponentArray<T>()->HasData(entity);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
T& GetComponent(Entity entity) {
|
||||
return GetComponentArray<T>()->GetData(entity);
|
||||
}
|
||||
|
||||
void EntityDestroyed(Entity entity) {
|
||||
for (auto const& pair : componentArrays) {
|
||||
auto const& component = pair.second;
|
||||
component->EntityDestroyed(entity);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
std::unordered_map<std::type_index, std::shared_ptr<IComponentArray>> componentArrays;
|
||||
|
||||
template<typename T>
|
||||
std::shared_ptr<ComponentArray<T>> GetComponentArray() const {
|
||||
const std::type_index typeName = typeid(T);
|
||||
auto it = componentArrays.find(typeName);
|
||||
if (it == componentArrays.end()) {
|
||||
throw std::runtime_error("Component not registered.");
|
||||
}
|
||||
return std::static_pointer_cast<ComponentArray<T>>(it->second);
|
||||
}
|
||||
};
|
||||
|
||||
// EntityManager handles entity creation and destruction
|
||||
class EntityManager {
|
||||
public:
|
||||
EntityManager() : livingEntityCount(0) {}
|
||||
|
||||
void Init() {
|
||||
for (Entity entity = 0; entity < MAX_ENTITIES; ++entity)
|
||||
availableEntities.push_back(entity);
|
||||
}
|
||||
|
||||
Entity CreateEntity() {
|
||||
if (livingEntityCount >= MAX_ENTITIES) {
|
||||
throw std::runtime_error("Too many entities in existence.");
|
||||
}
|
||||
Entity id = availableEntities.back();
|
||||
availableEntities.pop_back();
|
||||
activeEntities.emplace_back(id);
|
||||
++livingEntityCount;
|
||||
return id;
|
||||
}
|
||||
|
||||
void DestroyEntity(Entity entity, ComponentManager& cm) {
|
||||
if (entity >= MAX_ENTITIES) {
|
||||
return;
|
||||
}
|
||||
availableEntities.push_back(entity);
|
||||
activeEntities.erase(std::remove(activeEntities.begin(), activeEntities.end(), entity), activeEntities.end());
|
||||
cm.EntityDestroyed(entity);
|
||||
--livingEntityCount;
|
||||
}
|
||||
|
||||
const std::vector<Entity>& GetActiveEntities() const { return activeEntities; }
|
||||
|
||||
private:
|
||||
std::vector<Entity> availableEntities{};
|
||||
std::vector<Entity> activeEntities{};
|
||||
uint32_t livingEntityCount;
|
||||
};
|
230
src/Engine.cpp
Normal file
230
src/Engine.cpp
Normal file
@ -0,0 +1,230 @@
|
||||
// src/Engine.cpp
|
||||
|
||||
#include "Engine.h"
|
||||
#include <cstdio>
|
||||
#include <chrono>
|
||||
#include <GL/glew.h>
|
||||
#include <GLFW/glfw3.h>
|
||||
|
||||
// Dear ImGui
|
||||
#include "imgui.h"
|
||||
#include "imgui_impl_glfw.h"
|
||||
#include "imgui_impl_opengl3.h"
|
||||
|
||||
#include "Windows/RenderWindow.h"
|
||||
#include "Windows/PerformanceWindow.h"
|
||||
#include "Windows/LoggerWindow.h"
|
||||
|
||||
bool MyEngine::Init(int width, int height, const std::string& title)
|
||||
{
|
||||
// ------------------------------------------
|
||||
// 1) Initialize GLFW
|
||||
// ------------------------------------------
|
||||
if (!glfwInit())
|
||||
{
|
||||
fprintf(stderr, "[Engine] Failed to initialize GLFW\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Setup hints for OpenGL 3.3 Core
|
||||
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
|
||||
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
|
||||
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
|
||||
|
||||
// Create window
|
||||
m_Window = glfwCreateWindow(width, height, title.c_str(), nullptr, nullptr);
|
||||
if (!m_Window)
|
||||
{
|
||||
fprintf(stderr, "[Engine] Failed to create GLFW window\n");
|
||||
glfwTerminate();
|
||||
return false;
|
||||
}
|
||||
glfwMakeContextCurrent(m_Window);
|
||||
glfwSwapInterval(1); // vsync
|
||||
|
||||
// ------------------------------------------
|
||||
// 2) Initialize GLEW
|
||||
// ------------------------------------------
|
||||
if (glewInit() != GLEW_OK)
|
||||
{
|
||||
fprintf(stderr, "[Engine] Failed to initialize GLEW\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
// ------------------------------------------
|
||||
// 3) Initialize ImGui
|
||||
// ------------------------------------------
|
||||
IMGUI_CHECKVERSION();
|
||||
ImGui::CreateContext();
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
(void)io;
|
||||
// Enable docking
|
||||
io.ConfigFlags |= ImGuiConfigFlags_DockingEnable;
|
||||
// (Optional) Multi-viewport
|
||||
// io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable;
|
||||
|
||||
// Style
|
||||
ImGui::StyleColorsDark();
|
||||
|
||||
// Platform/Renderer bindings
|
||||
ImGui_ImplGlfw_InitForOpenGL(m_Window, true);
|
||||
ImGui_ImplOpenGL3_Init("#version 330");
|
||||
|
||||
// Initialize windows
|
||||
m_RenderWindow = std::make_unique<RenderWindow>();
|
||||
m_PerformanceWindow = std::make_unique<PerformanceWindow>();
|
||||
m_LoggerWindow = std::make_unique<LoggerWindow>();
|
||||
|
||||
// Some initial logs
|
||||
m_LoggerWindow->AddLog("Engine initialized.");
|
||||
m_LoggerWindow->AddLog("Welcome to Tesseract Engine!");
|
||||
|
||||
m_Running = true;
|
||||
m_LastTime = glfwGetTime();
|
||||
return true;
|
||||
}
|
||||
|
||||
void MyEngine::Run()
|
||||
{
|
||||
while (!glfwWindowShouldClose(m_Window) && m_Running)
|
||||
{
|
||||
// Poll
|
||||
glfwPollEvents();
|
||||
|
||||
// Calculate FPS
|
||||
double current_time = glfwGetTime();
|
||||
double delta = current_time - m_LastTime;
|
||||
m_FrameCount++;
|
||||
if (delta >= 1.0)
|
||||
{
|
||||
m_Fps = (float)(m_FrameCount / delta);
|
||||
m_Ms = 1000.0f / m_Fps;
|
||||
m_FrameCount = 0;
|
||||
m_LastTime = current_time;
|
||||
}
|
||||
|
||||
// Start new frame
|
||||
BeginFrame();
|
||||
|
||||
// Show main DockSpace
|
||||
ShowDockSpace();
|
||||
|
||||
// Show our windows
|
||||
m_RenderWindow->Show(); // The spinning triangle as ImGui::Image
|
||||
m_PerformanceWindow->Show(m_Fps, m_Ms); // FPS & ms
|
||||
m_LoggerWindow->Show(); // Logs
|
||||
|
||||
// End frame
|
||||
EndFrame();
|
||||
}
|
||||
}
|
||||
|
||||
void MyEngine::Cleanup()
|
||||
{
|
||||
// ImGui cleanup
|
||||
ImGui_ImplOpenGL3_Shutdown();
|
||||
ImGui_ImplGlfw_Shutdown();
|
||||
ImGui::DestroyContext();
|
||||
|
||||
// GLFW cleanup
|
||||
if (m_Window)
|
||||
{
|
||||
glfwDestroyWindow(m_Window);
|
||||
m_Window = nullptr;
|
||||
}
|
||||
glfwTerminate();
|
||||
|
||||
m_Running = false;
|
||||
}
|
||||
|
||||
void MyEngine::BeginFrame()
|
||||
{
|
||||
// ImGui new frame
|
||||
ImGui_ImplOpenGL3_NewFrame();
|
||||
ImGui_ImplGlfw_NewFrame();
|
||||
ImGui::NewFrame();
|
||||
}
|
||||
|
||||
void MyEngine::EndFrame()
|
||||
{
|
||||
// Render ImGui
|
||||
ImGui::Render();
|
||||
|
||||
// Clear the default framebuffer
|
||||
int display_w, display_h;
|
||||
glfwGetFramebufferSize(m_Window, &display_w, &display_h);
|
||||
glViewport(0, 0, display_w, display_h);
|
||||
glClearColor(0.05f, 0.05f, 0.06f, 1.0f);
|
||||
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
||||
|
||||
// Draw the ImGui data
|
||||
ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData());
|
||||
|
||||
// (Optional) handle multi-viewport
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable)
|
||||
{
|
||||
GLFWwindow* backup_current_context = glfwGetCurrentContext();
|
||||
ImGui::UpdatePlatformWindows();
|
||||
ImGui::RenderPlatformWindowsDefault();
|
||||
glfwMakeContextCurrent(backup_current_context);
|
||||
}
|
||||
|
||||
// Swap
|
||||
glfwSwapBuffers(m_Window);
|
||||
}
|
||||
|
||||
void MyEngine::ShowDockSpace()
|
||||
{
|
||||
static bool dockspaceOpen = true;
|
||||
static bool opt_fullscreen = true;
|
||||
static ImGuiDockNodeFlags dockspace_flags = ImGuiDockNodeFlags_None;
|
||||
|
||||
ImGuiWindowFlags window_flags = ImGuiWindowFlags_MenuBar | ImGuiWindowFlags_NoDocking;
|
||||
if (opt_fullscreen)
|
||||
{
|
||||
ImGuiViewport* viewport = ImGui::GetMainViewport();
|
||||
ImGui::SetNextWindowPos(viewport->WorkPos);
|
||||
ImGui::SetNextWindowSize(viewport->WorkSize);
|
||||
ImGui::SetNextWindowViewport(viewport->ID);
|
||||
window_flags |= ImGuiWindowFlags_NoTitleBar
|
||||
| ImGuiWindowFlags_NoCollapse
|
||||
| ImGuiWindowFlags_NoResize
|
||||
| ImGuiWindowFlags_NoMove;
|
||||
window_flags |= ImGuiWindowFlags_NoBringToFrontOnFocus
|
||||
| ImGuiWindowFlags_NoNavFocus;
|
||||
}
|
||||
|
||||
// Style
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_WindowRounding, 0.0f);
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_WindowBorderSize, 0.0f);
|
||||
|
||||
ImGui::Begin("DockSpace", &dockspaceOpen, window_flags);
|
||||
ImGui::PopStyleVar(2);
|
||||
|
||||
// Menu bar example
|
||||
if (ImGui::BeginMenuBar())
|
||||
{
|
||||
if (ImGui::BeginMenu("File"))
|
||||
{
|
||||
if (ImGui::MenuItem("Exit"))
|
||||
m_Running = false; // Stop the engine
|
||||
ImGui::EndMenu();
|
||||
}
|
||||
ImGui::EndMenuBar();
|
||||
}
|
||||
|
||||
// DockSpace
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
if (io.ConfigFlags & ImGuiConfigFlags_DockingEnable)
|
||||
{
|
||||
ImGuiID dockspace_id = ImGui::GetID("MyDockSpace");
|
||||
ImGui::DockSpace(dockspace_id, ImVec2(0.0f, 0.0f), dockspace_flags);
|
||||
}
|
||||
else
|
||||
{
|
||||
ImGui::Text("Docking is not enabled. Set io.ConfigFlags |= ImGuiConfigFlags_DockingEnable.");
|
||||
}
|
||||
|
||||
ImGui::End();
|
||||
}
|
41
src/Engine.h
Normal file
41
src/Engine.h
Normal file
@ -0,0 +1,41 @@
|
||||
// src/Engine.h
|
||||
|
||||
#pragma once
|
||||
#include <string>
|
||||
#include <memory>
|
||||
#include "Windows/RenderWindow.h"
|
||||
#include "Windows/PerformanceWindow.h"
|
||||
#include "Windows/LoggerWindow.h"
|
||||
|
||||
// Forward declaration to avoid including GLFW in the header if you prefer
|
||||
struct GLFWwindow;
|
||||
|
||||
// The main engine class that owns the application loop
|
||||
class MyEngine
|
||||
{
|
||||
public:
|
||||
bool Init(int width, int height, const std::string& title);
|
||||
void Run();
|
||||
void Cleanup();
|
||||
|
||||
private:
|
||||
// Internal helpers
|
||||
void BeginFrame();
|
||||
void EndFrame();
|
||||
void ShowDockSpace();
|
||||
|
||||
private:
|
||||
GLFWwindow* m_Window = nullptr;
|
||||
bool m_Running = false;
|
||||
|
||||
// Windows
|
||||
std::unique_ptr<RenderWindow> m_RenderWindow;
|
||||
std::unique_ptr<PerformanceWindow> m_PerformanceWindow;
|
||||
std::unique_ptr<LoggerWindow> m_LoggerWindow;
|
||||
|
||||
// For FPS calculation
|
||||
float m_Fps = 0.0f;
|
||||
float m_Ms = 0.0f;
|
||||
double m_LastTime = 0.0;
|
||||
int m_FrameCount = 0;
|
||||
};
|
@ -1,28 +0,0 @@
|
||||
// src/Logger.cpp
|
||||
#include "Logger.h"
|
||||
|
||||
// Initialize the Singleton instance
|
||||
Logger& Logger::GetInstance() {
|
||||
static Logger instance;
|
||||
return instance;
|
||||
}
|
||||
|
||||
// Private constructor
|
||||
Logger::Logger() : max_entries(1000) {}
|
||||
|
||||
// Log a message
|
||||
void Logger::Log(LogLevel level, const std::string& message) {
|
||||
entries.emplace_back(LogEntry{ level, message });
|
||||
if (entries.size() > max_entries)
|
||||
entries.erase(entries.begin());
|
||||
}
|
||||
|
||||
// Get all log entries
|
||||
const std::vector<LogEntry>& Logger::GetEntries() const {
|
||||
return entries;
|
||||
}
|
||||
|
||||
// Clear all log entries
|
||||
void Logger::Clear() {
|
||||
entries.clear();
|
||||
}
|
30
src/Logger.h
30
src/Logger.h
@ -1,30 +0,0 @@
|
||||
// src/Logger.h
|
||||
#pragma once
|
||||
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <cstdint>
|
||||
|
||||
// Enum for log levels
|
||||
enum class LogLevel { INFO, WARNING, ERROR };
|
||||
|
||||
// Struct to represent a log entry
|
||||
struct LogEntry {
|
||||
LogLevel level;
|
||||
std::string message;
|
||||
};
|
||||
|
||||
// Logger class (Singleton)
|
||||
class Logger {
|
||||
public:
|
||||
static Logger& GetInstance();
|
||||
|
||||
void Log(LogLevel level, const std::string& message);
|
||||
const std::vector<LogEntry>& GetEntries() const;
|
||||
void Clear();
|
||||
|
||||
private:
|
||||
Logger(); // Private constructor for Singleton
|
||||
std::vector<LogEntry> entries;
|
||||
size_t max_entries;
|
||||
};
|
@ -1,22 +0,0 @@
|
||||
// src/MeshComponent.h
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <glm/glm.hpp>
|
||||
#include <GL/glew.h>
|
||||
|
||||
|
||||
struct Vertex {
|
||||
glm::vec3 Position;
|
||||
glm::vec3 Normal;
|
||||
glm::vec2 TexCoords;
|
||||
};
|
||||
|
||||
struct MeshComponent {
|
||||
std::vector<Vertex> vertices;
|
||||
std::vector<unsigned int> indices;
|
||||
GLuint VAO, VBO, EBO;
|
||||
|
||||
MeshComponent() : VAO(0), VBO(0), EBO(0) {}
|
||||
};
|
57
src/Meshes.h
57
src/Meshes.h
@ -1,57 +0,0 @@
|
||||
// src/Meshes.h
|
||||
#pragma once
|
||||
|
||||
#include "MeshComponent.h"
|
||||
|
||||
MeshComponent CreateCubeMesh() {
|
||||
MeshComponent mesh;
|
||||
|
||||
// Define cube vertices
|
||||
Vertex v1 = { glm::vec3(-0.5f, -0.5f, -0.5f), glm::vec3(0.0f, 0.0f, -1.0f), glm::vec2(0.0f, 0.0f) };
|
||||
Vertex v2 = { glm::vec3( 0.5f, -0.5f, -0.5f), glm::vec3(0.0f, 0.0f, -1.0f), glm::vec2(1.0f, 0.0f) };
|
||||
Vertex v3 = { glm::vec3( 0.5f, 0.5f, -0.5f), glm::vec3(0.0f, 0.0f, -1.0f), glm::vec2(1.0f, 1.0f) };
|
||||
Vertex v4 = { glm::vec3(-0.5f, 0.5f, -0.5f), glm::vec3(0.0f, 0.0f, -1.0f), glm::vec2(0.0f, 1.0f) };
|
||||
// ... define other vertices for the cube
|
||||
|
||||
// For brevity, only defining front face. Define all 6 faces similarly.
|
||||
|
||||
// Front face
|
||||
mesh.vertices = {
|
||||
v1, v2, v3, v4,
|
||||
// Define other vertices
|
||||
};
|
||||
|
||||
// Define indices
|
||||
mesh.indices = {
|
||||
0, 1, 2,
|
||||
2, 3, 0,
|
||||
// Define other indices for other faces
|
||||
};
|
||||
|
||||
// Generate buffers
|
||||
glGenVertexArrays(1, &mesh.VAO);
|
||||
glGenBuffers(1, &mesh.VBO);
|
||||
glGenBuffers(1, &mesh.EBO);
|
||||
|
||||
glBindVertexArray(mesh.VAO);
|
||||
|
||||
glBindBuffer(GL_ARRAY_BUFFER, mesh.VBO);
|
||||
glBufferData(GL_ARRAY_BUFFER, mesh.vertices.size() * sizeof(Vertex), &mesh.vertices[0], GL_STATIC_DRAW);
|
||||
|
||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mesh.EBO);
|
||||
glBufferData(GL_ELEMENT_ARRAY_BUFFER, mesh.indices.size() * sizeof(unsigned int), &mesh.indices[0], GL_STATIC_DRAW);
|
||||
|
||||
// Position attribute
|
||||
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)0);
|
||||
glEnableVertexAttribArray(0);
|
||||
// Normal attribute
|
||||
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)offsetof(Vertex, Normal));
|
||||
glEnableVertexAttribArray(1);
|
||||
// Texture coords attribute
|
||||
glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)offsetof(Vertex, TexCoords));
|
||||
glEnableVertexAttribArray(2);
|
||||
|
||||
glBindVertexArray(0);
|
||||
|
||||
return mesh;
|
||||
}
|
81
src/Rendering/FBO.cpp
Normal file
81
src/Rendering/FBO.cpp
Normal file
@ -0,0 +1,81 @@
|
||||
// src/Rendering/FBO.cpp
|
||||
|
||||
#include "FBO.h"
|
||||
#include <cstdio>
|
||||
|
||||
bool FBO::Create(int width, int height)
|
||||
{
|
||||
Cleanup(); // In case we already had one
|
||||
|
||||
m_Width = width;
|
||||
m_Height = height;
|
||||
|
||||
// 1) Generate FBO
|
||||
glGenFramebuffers(1, &m_FBO);
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, m_FBO);
|
||||
|
||||
// 2) Create Texture
|
||||
glGenTextures(1, &m_TextureID);
|
||||
glBindTexture(GL_TEXTURE_2D, m_TextureID);
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0,
|
||||
GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
|
||||
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
|
||||
GL_TEXTURE_2D, m_TextureID, 0);
|
||||
|
||||
// 3) Create RBO for depth/stencil
|
||||
glGenRenderbuffers(1, &m_RBO);
|
||||
glBindRenderbuffer(GL_RENDERBUFFER, m_RBO);
|
||||
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, width, height);
|
||||
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT,
|
||||
GL_RENDERBUFFER, m_RBO);
|
||||
|
||||
// 4) Check completeness
|
||||
if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
|
||||
{
|
||||
fprintf(stderr, "[FBO] Framebuffer not complete!\n");
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
||||
Cleanup();
|
||||
return false;
|
||||
}
|
||||
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
||||
return true;
|
||||
}
|
||||
|
||||
void FBO::Cleanup()
|
||||
{
|
||||
if (m_TextureID)
|
||||
{
|
||||
glDeleteTextures(1, &m_TextureID);
|
||||
m_TextureID = 0;
|
||||
}
|
||||
if (m_RBO)
|
||||
{
|
||||
glDeleteRenderbuffers(1, &m_RBO);
|
||||
m_RBO = 0;
|
||||
}
|
||||
if (m_FBO)
|
||||
{
|
||||
glDeleteFramebuffers(1, &m_FBO);
|
||||
m_FBO = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void FBO::Bind()
|
||||
{
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, m_FBO);
|
||||
}
|
||||
|
||||
void FBO::Unbind()
|
||||
{
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
||||
}
|
||||
|
||||
ImTextureID FBO::GetTextureID() const
|
||||
{
|
||||
// For OpenGL + ImGui, typically cast GLuint to (ImTextureID) via uintptr_t
|
||||
return (ImTextureID)(uintptr_t)m_TextureID;
|
||||
}
|
37
src/Rendering/FBO.h
Normal file
37
src/Rendering/FBO.h
Normal file
@ -0,0 +1,37 @@
|
||||
// src/Rendering/FBO.h
|
||||
|
||||
#pragma once
|
||||
#include <GL/glew.h>
|
||||
#include "imgui.h"
|
||||
|
||||
// A simple FBO wrapper
|
||||
class FBO
|
||||
{
|
||||
public:
|
||||
FBO() = default;
|
||||
~FBO() { Cleanup(); }
|
||||
|
||||
// Create the FBO with a given size
|
||||
bool Create(int width, int height);
|
||||
|
||||
// Cleanup
|
||||
void Cleanup();
|
||||
|
||||
// Bind / Unbind
|
||||
void Bind();
|
||||
static void Unbind();
|
||||
|
||||
// The texture ID to use in ImGui::Image()
|
||||
ImTextureID GetTextureID() const;
|
||||
|
||||
// Size info
|
||||
int GetWidth() const { return m_Width; }
|
||||
int GetHeight() const { return m_Height; }
|
||||
|
||||
private:
|
||||
GLuint m_FBO = 0;
|
||||
GLuint m_TextureID = 0;
|
||||
GLuint m_RBO = 0;
|
||||
int m_Width = 0;
|
||||
int m_Height = 0;
|
||||
};
|
95
src/Rendering/Shader.cpp
Normal file
95
src/Rendering/Shader.cpp
Normal file
@ -0,0 +1,95 @@
|
||||
#include "Shader.h"
|
||||
#include <fstream>
|
||||
#include <sstream>
|
||||
#include <iostream>
|
||||
|
||||
Shader::~Shader()
|
||||
{
|
||||
if (m_ProgramID)
|
||||
glDeleteProgram(m_ProgramID);
|
||||
}
|
||||
|
||||
bool Shader::Load(const std::string& vertexPath, const std::string& fragmentPath)
|
||||
{
|
||||
// 1) Create shader objects
|
||||
GLuint vertexShader = glCreateShader(GL_VERTEX_SHADER);
|
||||
GLuint fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
|
||||
|
||||
// 2) Load sources
|
||||
std::string vertSource = LoadSourceFromFile(vertexPath);
|
||||
std::string fragSource = LoadSourceFromFile(fragmentPath);
|
||||
if (vertSource.empty() || fragSource.empty())
|
||||
{
|
||||
std::cerr << "[Shader] Failed to read shader files." << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
// 3) Compile vertex shader
|
||||
{
|
||||
const char* src = vertSource.c_str();
|
||||
glShaderSource(vertexShader, 1, &src, nullptr);
|
||||
glCompileShader(vertexShader);
|
||||
if (!CompileShader(vertexShader, vertexPath))
|
||||
return false;
|
||||
}
|
||||
|
||||
// 4) Compile fragment shader
|
||||
{
|
||||
const char* src = fragSource.c_str();
|
||||
glShaderSource(fragmentShader, 1, &src, nullptr);
|
||||
glCompileShader(fragmentShader);
|
||||
if (!CompileShader(fragmentShader, fragmentPath))
|
||||
return false;
|
||||
}
|
||||
|
||||
// 5) Create program and link
|
||||
m_ProgramID = glCreateProgram();
|
||||
glAttachShader(m_ProgramID, vertexShader);
|
||||
glAttachShader(m_ProgramID, fragmentShader);
|
||||
glLinkProgram(m_ProgramID);
|
||||
|
||||
// Check link status
|
||||
GLint success;
|
||||
glGetProgramiv(m_ProgramID, GL_LINK_STATUS, &success);
|
||||
if (!success)
|
||||
{
|
||||
char infoLog[1024];
|
||||
glGetProgramInfoLog(m_ProgramID, 1024, nullptr, infoLog);
|
||||
std::cerr << "[Shader] Program linking failed:\n" << infoLog << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
// Cleanup shader objects after linking
|
||||
glDeleteShader(vertexShader);
|
||||
glDeleteShader(fragmentShader);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Shader::CompileShader(GLuint shaderID, const std::string& filePath)
|
||||
{
|
||||
GLint success;
|
||||
glGetShaderiv(shaderID, GL_COMPILE_STATUS, &success);
|
||||
if (!success)
|
||||
{
|
||||
char infoLog[1024];
|
||||
glGetShaderInfoLog(shaderID, 1024, nullptr, infoLog);
|
||||
std::cerr << "[Shader] Compilation error in " << filePath << ":\n"
|
||||
<< infoLog << std::endl;
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
std::string Shader::LoadSourceFromFile(const std::string& filePath)
|
||||
{
|
||||
std::ifstream file(filePath);
|
||||
if (!file.is_open())
|
||||
{
|
||||
std::cerr << "[Shader] Could not open file: " << filePath << std::endl;
|
||||
return "";
|
||||
}
|
||||
std::stringstream buffer;
|
||||
buffer << file.rdbuf();
|
||||
return buffer.str();
|
||||
}
|
25
src/Rendering/Shader.h
Normal file
25
src/Rendering/Shader.h
Normal file
@ -0,0 +1,25 @@
|
||||
#pragma once
|
||||
#include <string>
|
||||
#include <GL/glew.h>
|
||||
|
||||
class Shader
|
||||
{
|
||||
public:
|
||||
Shader() = default;
|
||||
~Shader();
|
||||
|
||||
// Load & compile from files (vertex & fragment)
|
||||
bool Load(const std::string& vertexPath, const std::string& fragmentPath);
|
||||
|
||||
void Use() const { glUseProgram(m_ProgramID); }
|
||||
|
||||
// Uniform helper
|
||||
GLuint GetProgramID() const { return m_ProgramID; }
|
||||
|
||||
private:
|
||||
bool CompileShader(GLuint shaderID, const std::string& source);
|
||||
std::string LoadSourceFromFile(const std::string& filePath);
|
||||
|
||||
private:
|
||||
GLuint m_ProgramID = 0;
|
||||
};
|
@ -1,120 +0,0 @@
|
||||
// src/ShaderComponent.cpp
|
||||
#include "ShaderComponent.h"
|
||||
#include "Logger.h"
|
||||
|
||||
#include <fstream>
|
||||
#include <sstream>
|
||||
#include <iostream>
|
||||
|
||||
Shader::Shader(const char* vertexPath, const char* fragmentPath)
|
||||
{
|
||||
// 1. Retrieve the vertex/fragment source code from filePath
|
||||
std::string vertexCode;
|
||||
std::string fragmentCode;
|
||||
std::ifstream vShaderFile;
|
||||
std::ifstream fShaderFile;
|
||||
|
||||
// Ensure ifstream objects can throw exceptions:
|
||||
vShaderFile.exceptions (std::ifstream::failbit | std::ifstream::badbit);
|
||||
fShaderFile.exceptions (std::ifstream::failbit | std::ifstream::badbit);
|
||||
try
|
||||
{
|
||||
// Open files
|
||||
vShaderFile.open(vertexPath);
|
||||
fShaderFile.open(fragmentPath);
|
||||
std::stringstream vShaderStream, fShaderStream;
|
||||
|
||||
// Read file's buffer contents into streams
|
||||
vShaderStream << vShaderFile.rdbuf();
|
||||
fShaderStream << fShaderFile.rdbuf();
|
||||
|
||||
// Close file handlers
|
||||
vShaderFile.close();
|
||||
fShaderFile.close();
|
||||
|
||||
// Convert stream into string
|
||||
vertexCode = vShaderStream.str();
|
||||
fragmentCode = fShaderStream.str();
|
||||
}
|
||||
catch(std::ifstream::failure& e)
|
||||
{
|
||||
Logger::GetInstance().Log(LogLevel::ERROR, "ERROR::SHADER::FILE_NOT_SUCCESFULLY_READ");
|
||||
}
|
||||
const char* vShaderCode = vertexCode.c_str();
|
||||
const char * fShaderCode = fragmentCode.c_str();
|
||||
|
||||
// 2. Compile shaders
|
||||
GLuint vertex, fragment;
|
||||
int success;
|
||||
char infoLog[512];
|
||||
|
||||
// Vertex Shader
|
||||
vertex = glCreateShader(GL_VERTEX_SHADER);
|
||||
glShaderSource(vertex, 1, &vShaderCode, NULL);
|
||||
glCompileShader(vertex);
|
||||
// Print compile errors if any
|
||||
glGetShaderiv(vertex, GL_COMPILE_STATUS, &success);
|
||||
if(!success)
|
||||
{
|
||||
glGetShaderInfoLog(vertex, 512, NULL, infoLog);
|
||||
Logger::GetInstance().Log(LogLevel::ERROR, std::string("ERROR::SHADER::VERTEX::COMPILATION_FAILED\n") + infoLog);
|
||||
};
|
||||
|
||||
// Fragment Shader
|
||||
fragment = glCreateShader(GL_FRAGMENT_SHADER);
|
||||
glShaderSource(fragment, 1, &fShaderCode, NULL);
|
||||
glCompileShader(fragment);
|
||||
// Print compile errors if any
|
||||
glGetShaderiv(fragment, GL_COMPILE_STATUS, &success);
|
||||
if(!success)
|
||||
{
|
||||
glGetShaderInfoLog(fragment, 512, NULL, infoLog);
|
||||
Logger::GetInstance().Log(LogLevel::ERROR, std::string("ERROR::SHADER::FRAGMENT::COMPILATION_FAILED\n") + infoLog);
|
||||
};
|
||||
|
||||
// Shader Program
|
||||
ID = glCreateProgram();
|
||||
glAttachShader(ID, vertex);
|
||||
glAttachShader(ID, fragment);
|
||||
glLinkProgram(ID);
|
||||
// Print linking errors if any
|
||||
glGetProgramiv(ID, GL_LINK_STATUS, &success);
|
||||
if(!success) {
|
||||
glGetProgramInfoLog(ID, 512, NULL, infoLog);
|
||||
Logger::GetInstance().Log(LogLevel::ERROR, std::string("ERROR::SHADER::PROGRAM::LINKING_FAILED\n") + infoLog);
|
||||
}
|
||||
|
||||
// Delete the shaders as they're linked into our program now and no longer necessary
|
||||
glDeleteShader(vertex);
|
||||
glDeleteShader(fragment);
|
||||
}
|
||||
|
||||
void Shader::Use()
|
||||
{
|
||||
glUseProgram(ID);
|
||||
}
|
||||
|
||||
void Shader::SetBool(const std::string &name, bool value) const
|
||||
{
|
||||
glUniform1i(glGetUniformLocation(ID, name.c_str()), (int)value);
|
||||
}
|
||||
|
||||
void Shader::SetInt(const std::string &name, int value) const
|
||||
{
|
||||
glUniform1i(glGetUniformLocation(ID, name.c_str()), value);
|
||||
}
|
||||
|
||||
void Shader::SetFloat(const std::string &name, float value) const
|
||||
{
|
||||
glUniform1f(glGetUniformLocation(ID, name.c_str()), value);
|
||||
}
|
||||
|
||||
void Shader::SetMat4(const std::string &name, const glm::mat4 &mat) const
|
||||
{
|
||||
glUniformMatrix4fv(glGetUniformLocation(ID, name.c_str()), 1, GL_FALSE, &mat[0][0]);
|
||||
}
|
||||
|
||||
void Shader::SetVec3(const std::string &name, const glm::vec3 &vec) const
|
||||
{
|
||||
glUniform3fv(glGetUniformLocation(ID, name.c_str()), 1, &vec[0]);
|
||||
}
|
@ -1,22 +0,0 @@
|
||||
// src/ShaderComponent.h
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <GL/glew.h>
|
||||
#include <glm/glm.hpp>
|
||||
|
||||
|
||||
|
||||
class Shader {
|
||||
public:
|
||||
GLuint ID;
|
||||
|
||||
Shader() : ID(0) {}
|
||||
Shader(const char* vertexPath, const char* fragmentPath);
|
||||
void Use();
|
||||
void SetBool(const std::string &name, bool value) const;
|
||||
void SetInt(const std::string &name, int value) const;
|
||||
void SetFloat(const std::string &name, float value) const;
|
||||
void SetMat4(const std::string &name, const glm::mat4 &mat) const;
|
||||
void SetVec3(const std::string &name, const glm::vec3 &vec) const;
|
||||
};
|
@ -1,59 +0,0 @@
|
||||
// src/TextureManager.cpp
|
||||
#include "TextureManager.h"
|
||||
#include "Logger.h"
|
||||
#include "stb_image.h"
|
||||
|
||||
GLuint TextureManager::LoadTexture(const std::string& path) {
|
||||
// Check if texture already loaded
|
||||
auto it = textures.find(path);
|
||||
if (it != textures.end()) {
|
||||
return it->second;
|
||||
}
|
||||
|
||||
// Load image
|
||||
int width, height, channels;
|
||||
unsigned char* data = stbi_load(path.c_str(), &width, &height, &channels, 4);
|
||||
if (!data) {
|
||||
Logger::GetInstance().Log(LogLevel::ERROR, "Failed to load texture: " + path);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Generate OpenGL texture
|
||||
GLuint textureID;
|
||||
glGenTextures(1, &textureID);
|
||||
glBindTexture(GL_TEXTURE_2D, textureID);
|
||||
// Set texture parameters
|
||||
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);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
// Upload texture data
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, data);
|
||||
//glGenerateMipmap(GL_TEXTURE_2D); // Uncomment if using mipmaps
|
||||
|
||||
glBindTexture(GL_TEXTURE_2D, 0);
|
||||
|
||||
// Free image data
|
||||
stbi_image_free(data);
|
||||
|
||||
// Store texture
|
||||
textures[path] = textureID;
|
||||
|
||||
Logger::GetInstance().Log(LogLevel::INFO, "Loaded texture: " + path);
|
||||
return textureID;
|
||||
}
|
||||
|
||||
GLuint TextureManager::GetTexture(const std::string& path) {
|
||||
auto it = textures.find(path);
|
||||
if (it != textures.end()) {
|
||||
return it->second;
|
||||
}
|
||||
return LoadTexture(path);
|
||||
}
|
||||
|
||||
void TextureManager::Cleanup() {
|
||||
for (auto& pair : textures) {
|
||||
glDeleteTextures(1, &pair.second);
|
||||
}
|
||||
textures.clear();
|
||||
}
|
@ -1,16 +0,0 @@
|
||||
// src/TextureManager.h
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
#include <GLFW/glfw3.h> // Ensure GLAD is included before GLFW in the main.cpp
|
||||
|
||||
class TextureManager {
|
||||
public:
|
||||
GLuint LoadTexture(const std::string& path);
|
||||
GLuint GetTexture(const std::string& path);
|
||||
void Cleanup();
|
||||
|
||||
private:
|
||||
std::unordered_map<std::string, GLuint> textures;
|
||||
};
|
260
src/UI.cpp
260
src/UI.cpp
@ -1,260 +0,0 @@
|
||||
// src/UI.cpp
|
||||
#include "UI.h"
|
||||
#include "Logger.h"
|
||||
#include "imgui.h"
|
||||
#include "imgui_impl_glfw.h"
|
||||
#include "imgui_impl_opengl3.h"
|
||||
|
||||
// Helper function to get color based on log level
|
||||
ImVec4 GetColorForLogLevel(LogLevel level)
|
||||
{
|
||||
switch (level)
|
||||
{
|
||||
case LogLevel::INFO:
|
||||
return ImVec4(1.0f, 1.0f, 1.0f, 1.0f); // White
|
||||
case LogLevel::WARNING:
|
||||
return ImVec4(1.0f, 1.0f, 0.0f, 1.0f); // Yellow
|
||||
case LogLevel::ERROR:
|
||||
return ImVec4(1.0f, 0.0f, 0.0f, 1.0f); // Red
|
||||
default:
|
||||
return ImVec4(1.0f, 1.0f, 1.0f, 1.0f);
|
||||
}
|
||||
}
|
||||
|
||||
// 1. Main Menu Bar
|
||||
void ShowMainMenuBar()
|
||||
{
|
||||
if (ImGui::BeginMainMenuBar())
|
||||
{
|
||||
if (ImGui::BeginMenu("File"))
|
||||
{
|
||||
if (ImGui::MenuItem("New", "Ctrl+N")) { /* Handle New */ }
|
||||
if (ImGui::MenuItem("Open", "Ctrl+O")) { /* Handle Open */ }
|
||||
if (ImGui::MenuItem("Save", "Ctrl+S")) { /* Handle Save */ }
|
||||
ImGui::Separator();
|
||||
if (ImGui::MenuItem("Exit")) { /* Handle Exit */ }
|
||||
ImGui::EndMenu();
|
||||
}
|
||||
if (ImGui::BeginMenu("Edit"))
|
||||
{
|
||||
if (ImGui::MenuItem("Undo", "Ctrl+Z")) { /* Handle Undo */ }
|
||||
if (ImGui::MenuItem("Redo", "Ctrl+Y")) { /* Handle Redo */ }
|
||||
ImGui::Separator();
|
||||
if (ImGui::MenuItem("Copy", "Ctrl+C")) { /* Handle Copy */ }
|
||||
if (ImGui::MenuItem("Paste", "Ctrl+V")) { /* Handle Paste */ }
|
||||
ImGui::EndMenu();
|
||||
}
|
||||
if (ImGui::BeginMenu("View"))
|
||||
{
|
||||
static bool show_console = true;
|
||||
if (ImGui::MenuItem("Show Console", NULL, &show_console)) { /* Toggle Console */ }
|
||||
// Add more view toggles as needed
|
||||
ImGui::EndMenu();
|
||||
}
|
||||
ImGui::EndMainMenuBar();
|
||||
}
|
||||
}
|
||||
|
||||
// 2. Viewport Panel
|
||||
void ShowViewport(TextureManager& textureManager, EntityManager& em, ComponentManager& cm)
|
||||
{
|
||||
ImGui::Begin("Viewport", NULL, ImGuiWindowFlags_NoCollapse);
|
||||
|
||||
// Get the size of the viewport
|
||||
ImVec2 viewport_size = ImGui::GetContentRegionAvail();
|
||||
|
||||
// Set viewport background to black
|
||||
ImDrawList* draw_list = ImGui::GetWindowDrawList();
|
||||
ImVec2 pos = ImGui::GetCursorScreenPos();
|
||||
ImVec2 rect_min = pos;
|
||||
ImVec2 rect_max = ImVec2(pos.x + viewport_size.x, pos.y + viewport_size.y);
|
||||
draw_list->AddRectFilled(rect_min, rect_max, IM_COL32(0, 0, 0, 255)); // Black background
|
||||
|
||||
// Iterate through active entities
|
||||
const auto& entities = em.GetActiveEntities();
|
||||
for (auto entity : entities) {
|
||||
if (cm.HasComponent<SpriteComponent>(entity) && cm.HasComponent<TransformComponent>(entity)) {
|
||||
auto& sprite = cm.GetComponent<SpriteComponent>(entity);
|
||||
auto& transform = cm.GetComponent<TransformComponent>(entity);
|
||||
|
||||
// Get texture ID
|
||||
GLuint textureID = textureManager.GetTexture(sprite.texturePath);
|
||||
if (textureID == 0) {
|
||||
continue; // Failed to load texture
|
||||
}
|
||||
|
||||
// Convert GLuint to ImTextureID
|
||||
ImTextureID imgui_tex_id = (ImTextureID)(intptr_t)textureID;
|
||||
|
||||
// Define size based on scale
|
||||
ImVec2 size(transform.scale.x, transform.scale.y);
|
||||
|
||||
// Define position based on position
|
||||
ImVec2 img_pos = ImVec2(pos.x + transform.position.x, pos.y + transform.position.y);
|
||||
ImVec2 img_size = ImVec2(img_pos.x + size.x, img_pos.y + size.y);
|
||||
|
||||
// Render the image
|
||||
draw_list->AddImage(imgui_tex_id, img_pos, img_size);
|
||||
}
|
||||
}
|
||||
|
||||
ImGui::End();
|
||||
}
|
||||
|
||||
// 3. Console Panel
|
||||
void ShowConsole(bool* p_open)
|
||||
{
|
||||
ImGui::Begin("Console", p_open, ImGuiWindowFlags_NoCollapse);
|
||||
|
||||
// Options menu
|
||||
if (ImGui::BeginPopupContextWindow())
|
||||
{
|
||||
if (ImGui::MenuItem("Clear")) {
|
||||
Logger::GetInstance().Clear();
|
||||
}
|
||||
ImGui::EndPopup();
|
||||
}
|
||||
|
||||
// Reserve enough left-over height for 1 separator and 1 input text
|
||||
ImGui::Separator();
|
||||
|
||||
// Begin child region for scrolling
|
||||
ImGui::BeginChild("ConsoleChild", ImVec2(0, 0), false, ImGuiWindowFlags_HorizontalScrollbar);
|
||||
|
||||
// Iterate through log entries
|
||||
for (const auto& entry : Logger::GetInstance().GetEntries())
|
||||
{
|
||||
ImVec4 color = GetColorForLogLevel(entry.level);
|
||||
ImGui::PushStyleColor(ImGuiCol_Text, color);
|
||||
ImGui::TextUnformatted(entry.message.c_str());
|
||||
ImGui::PopStyleColor();
|
||||
}
|
||||
|
||||
// Auto-scroll to the bottom
|
||||
ImGui::SetScrollHereY(1.0f);
|
||||
|
||||
ImGui::EndChild();
|
||||
|
||||
ImGui::End();
|
||||
}
|
||||
|
||||
// 4. Entity Tree
|
||||
void ShowEntityTree(EntityManager& em, ComponentManager& cm, Entity& selectedEntity)
|
||||
{
|
||||
ImGui::Begin("Entities");
|
||||
|
||||
// Button to create a new entity
|
||||
if (ImGui::Button("Add Entity")) {
|
||||
try {
|
||||
Entity newEntity = em.CreateEntity();
|
||||
Logger::GetInstance().Log(LogLevel::INFO, "Created Entity " + std::to_string(newEntity));
|
||||
}
|
||||
catch (const std::exception& e) {
|
||||
Logger::GetInstance().Log(LogLevel::ERROR, e.what());
|
||||
}
|
||||
}
|
||||
|
||||
ImGui::Separator();
|
||||
|
||||
// Iterate through active entities
|
||||
const auto& entities = em.GetActiveEntities();
|
||||
for (auto entity : entities) {
|
||||
char label[32];
|
||||
sprintf(label, "Entity %d", entity);
|
||||
if (ImGui::Selectable(label, selectedEntity == entity)) {
|
||||
selectedEntity = entity;
|
||||
}
|
||||
}
|
||||
|
||||
// Option to destroy the selected entity
|
||||
if (selectedEntity != UINT32_MAX) {
|
||||
ImGui::Separator();
|
||||
if (ImGui::Button("Delete Entity")) {
|
||||
em.DestroyEntity(selectedEntity, cm);
|
||||
Logger::GetInstance().Log(LogLevel::INFO, "Destroyed Entity " + std::to_string(selectedEntity));
|
||||
selectedEntity = UINT32_MAX;
|
||||
}
|
||||
}
|
||||
|
||||
ImGui::End();
|
||||
}
|
||||
|
||||
// 5. Inspector Panel
|
||||
void ShowInspector(EntityManager& em, ComponentManager& cm, Entity selectedEntity)
|
||||
{
|
||||
ImGui::Begin("Inspector");
|
||||
|
||||
if (selectedEntity == UINT32_MAX) {
|
||||
ImGui::Text("No entity selected.");
|
||||
ImGui::End();
|
||||
return;
|
||||
}
|
||||
|
||||
char label[32];
|
||||
sprintf(label, "Entity %d", selectedEntity);
|
||||
ImGui::Text("%s", label);
|
||||
ImGui::Separator();
|
||||
|
||||
// Display Transform Component
|
||||
if (cm.HasComponent<TransformComponent>(selectedEntity)) {
|
||||
if (ImGui::TreeNode("Transform")) {
|
||||
auto& transform = cm.GetComponent<TransformComponent>(selectedEntity);
|
||||
ImGui::DragFloat3("Position", &transform.position.x, 0.1f);
|
||||
ImGui::DragFloat3("Rotation", &transform.rotation.x, 0.1f);
|
||||
ImGui::DragFloat3("Scale", &transform.scale.x, 0.1f);
|
||||
|
||||
if (ImGui::Button("Remove Transform")) {
|
||||
cm.RemoveComponent<TransformComponent>(selectedEntity);
|
||||
Logger::GetInstance().Log(LogLevel::INFO, "Removed TransformComponent from Entity " + std::to_string(selectedEntity));
|
||||
ImGui::TreePop();
|
||||
ImGui::End();
|
||||
return;
|
||||
}
|
||||
|
||||
ImGui::TreePop();
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (ImGui::Button("Add Transform")) {
|
||||
cm.AddComponent<TransformComponent>(selectedEntity, TransformComponent());
|
||||
Logger::GetInstance().Log(LogLevel::INFO, "Added TransformComponent to Entity " + std::to_string(selectedEntity));
|
||||
}
|
||||
}
|
||||
|
||||
// Display Sprite Component
|
||||
if (cm.HasComponent<SpriteComponent>(selectedEntity)) {
|
||||
if (ImGui::TreeNode("Sprite")) {
|
||||
auto& sprite = cm.GetComponent<SpriteComponent>(selectedEntity);
|
||||
static char buffer[256];
|
||||
strncpy(buffer, sprite.texturePath.c_str(), sizeof(buffer));
|
||||
buffer[sizeof(buffer) - 1] = '\0'; // Ensure null-termination
|
||||
if (ImGui::InputText("Texture Path", buffer, sizeof(buffer))) {
|
||||
std::string newPath(buffer);
|
||||
if (newPath != sprite.texturePath) {
|
||||
sprite.texturePath = newPath;
|
||||
Logger::GetInstance().Log(LogLevel::INFO, "Updated SpriteComponent texture path to " + newPath + " for Entity " + std::to_string(selectedEntity));
|
||||
}
|
||||
}
|
||||
|
||||
if (ImGui::Button("Remove Sprite")) {
|
||||
cm.RemoveComponent<SpriteComponent>(selectedEntity);
|
||||
Logger::GetInstance().Log(LogLevel::INFO, "Removed SpriteComponent from Entity " + std::to_string(selectedEntity));
|
||||
ImGui::TreePop();
|
||||
ImGui::End();
|
||||
return;
|
||||
}
|
||||
|
||||
ImGui::TreePop();
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (ImGui::Button("Add Sprite")) {
|
||||
// Assign a default path; ensure the texture exists
|
||||
std::string defaultPath = "assets/textures/default.png";
|
||||
cm.AddComponent<SpriteComponent>(selectedEntity, SpriteComponent(defaultPath));
|
||||
Logger::GetInstance().Log(LogLevel::INFO, "Added SpriteComponent to Entity " + std::to_string(selectedEntity) + " with texture path: " + defaultPath);
|
||||
}
|
||||
}
|
||||
|
||||
ImGui::End();
|
||||
}
|
13
src/UI.h
13
src/UI.h
@ -1,13 +0,0 @@
|
||||
// src/UI.h
|
||||
#pragma once
|
||||
|
||||
#include <GLFW/glfw3.h>
|
||||
#include "ECS.h"
|
||||
#include "TextureManager.h" // Include TextureManager.h
|
||||
|
||||
// Function declarations for UI panels
|
||||
void ShowMainMenuBar();
|
||||
void ShowViewport(TextureManager& textureManager, EntityManager& em, ComponentManager& cm);
|
||||
void ShowConsole(bool* p_open);
|
||||
void ShowEntityTree(EntityManager& em, ComponentManager& cm, Entity& selectedEntity);
|
||||
void ShowInspector(EntityManager& em, ComponentManager& cm, Entity selectedEntity);
|
31
src/Windows/LoggerWindow.cpp
Normal file
31
src/Windows/LoggerWindow.cpp
Normal file
@ -0,0 +1,31 @@
|
||||
// src/Windows/LoggerWindow.cpp
|
||||
|
||||
#include "LoggerWindow.h"
|
||||
#include "imgui.h"
|
||||
#include <cstdarg>
|
||||
#include <cstdio>
|
||||
|
||||
void LoggerWindow::AddLog(const char* fmt, ...)
|
||||
{
|
||||
char buffer[1024];
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
vsnprintf(buffer, sizeof(buffer), fmt, args);
|
||||
va_end(args);
|
||||
|
||||
m_Logs.push_back(buffer);
|
||||
}
|
||||
|
||||
void LoggerWindow::Show()
|
||||
{
|
||||
ImGui::Begin("Logger");
|
||||
|
||||
if (ImGui::Button("Clear"))
|
||||
m_Logs.clear();
|
||||
|
||||
ImGui::Separator();
|
||||
for (const auto& logLine : m_Logs)
|
||||
ImGui::TextUnformatted(logLine.c_str());
|
||||
|
||||
ImGui::End();
|
||||
}
|
18
src/Windows/LoggerWindow.h
Normal file
18
src/Windows/LoggerWindow.h
Normal file
@ -0,0 +1,18 @@
|
||||
// src/Windows/LoggerWindow.h
|
||||
|
||||
#pragma once
|
||||
#include <vector>
|
||||
#include <string>
|
||||
|
||||
class LoggerWindow
|
||||
{
|
||||
public:
|
||||
// Add logs from anywhere
|
||||
void AddLog(const char* fmt, ...);
|
||||
|
||||
// Show the ImGui window
|
||||
void Show();
|
||||
|
||||
private:
|
||||
std::vector<std::string> m_Logs;
|
||||
};
|
14
src/Windows/PerformanceWindow.cpp
Normal file
14
src/Windows/PerformanceWindow.cpp
Normal file
@ -0,0 +1,14 @@
|
||||
// src/Windows/PerformanceWindow.cpp
|
||||
|
||||
#include "PerformanceWindow.h"
|
||||
#include "imgui.h"
|
||||
|
||||
void PerformanceWindow::Show(float fps, float ms)
|
||||
{
|
||||
ImGui::Begin("Performance");
|
||||
ImGui::Text("FPS: %.1f", fps);
|
||||
ImGui::Text("ms/frame: %.3f ms", ms);
|
||||
ImGui::Separator();
|
||||
ImGui::Text("You can display more stats here (CPU/GPU usage, etc.)");
|
||||
ImGui::End();
|
||||
}
|
9
src/Windows/PerformanceWindow.h
Normal file
9
src/Windows/PerformanceWindow.h
Normal file
@ -0,0 +1,9 @@
|
||||
// src/Windows/PerformanceWindow.h
|
||||
|
||||
#pragma once
|
||||
|
||||
class PerformanceWindow
|
||||
{
|
||||
public:
|
||||
void Show(float fps, float ms);
|
||||
};
|
173
src/Windows/RenderWindow.cpp
Normal file
173
src/Windows/RenderWindow.cpp
Normal file
@ -0,0 +1,173 @@
|
||||
#include "RenderWindow.h"
|
||||
#include <GL/glew.h>
|
||||
#include <glm/gtc/matrix_transform.hpp> // for perspective, translate, rotate
|
||||
#include <glm/gtc/type_ptr.hpp> // for value_ptr
|
||||
#include "imgui.h"
|
||||
|
||||
// A simple data structure for a colored cube
|
||||
// position (x,y,z), color(r,g,b)
|
||||
static float g_CubeVertices[] = {
|
||||
// x, y, z, r, g, b
|
||||
// Front face
|
||||
-1.f, -1.f, 1.f, 1.f, 0.f, 0.f, // bottom-left
|
||||
1.f, -1.f, 1.f, 1.f, 0.f, 0.f, // bottom-right
|
||||
1.f, 1.f, 1.f, 1.f, 0.f, 0.f, // top-right
|
||||
-1.f, 1.f, 1.f, 1.f, 0.f, 0.f, // top-left
|
||||
|
||||
// Back face
|
||||
-1.f, -1.f, -1.f, 0.f, 1.f, 0.f,
|
||||
1.f, -1.f, -1.f, 0.f, 1.f, 0.f,
|
||||
1.f, 1.f, -1.f, 0.f, 1.f, 0.f,
|
||||
-1.f, 1.f, -1.f, 0.f, 1.f, 0.f,
|
||||
};
|
||||
|
||||
static unsigned int g_CubeIndices[] = {
|
||||
// Front face
|
||||
0, 1, 2,
|
||||
2, 3, 0,
|
||||
|
||||
// Back face
|
||||
5, 4, 7,
|
||||
7, 6, 5,
|
||||
|
||||
// Left face
|
||||
4, 0, 3,
|
||||
3, 7, 4,
|
||||
|
||||
// Right face
|
||||
1, 5, 6,
|
||||
6, 2, 1,
|
||||
|
||||
// Top face
|
||||
3, 2, 6,
|
||||
6, 7, 3,
|
||||
|
||||
// Bottom face
|
||||
4, 5, 1,
|
||||
1, 0, 4
|
||||
};
|
||||
|
||||
void RenderWindow::Show()
|
||||
{
|
||||
ImGui::Begin("OpenGL Output");
|
||||
|
||||
ImVec2 size = ImGui::GetContentRegionAvail();
|
||||
int w = (int)size.x;
|
||||
int h = (int)size.y;
|
||||
|
||||
// Lazy init, so we only do it once
|
||||
if (!m_Initialized)
|
||||
{
|
||||
InitGLResources();
|
||||
m_Initialized = true;
|
||||
}
|
||||
|
||||
if (w > 0 && h > 0)
|
||||
{
|
||||
// Re-create FBO if size changed
|
||||
if (w != m_LastWidth || h != m_LastHeight)
|
||||
{
|
||||
m_FBO.Create(w, h);
|
||||
m_LastWidth = w;
|
||||
m_LastHeight = h;
|
||||
}
|
||||
|
||||
// Render our scene to the FBO
|
||||
RenderSceneToFBO();
|
||||
|
||||
// Display the FBO texture in ImGui
|
||||
ImGui::Image(m_FBO.GetTextureID(), size, ImVec2(0,0), ImVec2(1,1));
|
||||
}
|
||||
else
|
||||
{
|
||||
ImGui::Text("No space to render.");
|
||||
}
|
||||
|
||||
ImGui::End();
|
||||
}
|
||||
|
||||
void RenderWindow::InitGLResources()
|
||||
{
|
||||
// 1) Load and compile our unlit shader
|
||||
// Adjust paths if needed. Ex: "shaders/UnlitMaterial.vert"
|
||||
if (!m_Shader.Load("shaders/UnlitMaterial.vert", "shaders/UnlitMaterial.frag"))
|
||||
{
|
||||
// Fail gracefully or throw
|
||||
fprintf(stderr, "[RenderWindow] Failed to load UnlitMaterial shader.\n");
|
||||
return;
|
||||
}
|
||||
|
||||
// 2) Create VAO
|
||||
glGenVertexArrays(1, &m_VAO);
|
||||
glBindVertexArray(m_VAO);
|
||||
|
||||
// 3) Create VBO
|
||||
glGenBuffers(1, &m_VBO);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, m_VBO);
|
||||
glBufferData(GL_ARRAY_BUFFER, sizeof(g_CubeVertices), g_CubeVertices, GL_STATIC_DRAW);
|
||||
|
||||
// 4) Create EBO
|
||||
glGenBuffers(1, &m_EBO);
|
||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_EBO);
|
||||
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(g_CubeIndices), g_CubeIndices, GL_STATIC_DRAW);
|
||||
|
||||
// 5) Setup vertex attribs:
|
||||
// layout(location = 0) => aPos (3 floats)
|
||||
// layout(location = 1) => aColor (3 floats)
|
||||
// Stride: 6 floats total
|
||||
// Positions start at offset 0
|
||||
// Color starts at offset 3 * sizeof(float)
|
||||
|
||||
// Position
|
||||
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(float), (void*)0);
|
||||
glEnableVertexAttribArray(0);
|
||||
|
||||
// Color
|
||||
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(float),
|
||||
(void*)(3 * sizeof(float)));
|
||||
glEnableVertexAttribArray(1);
|
||||
|
||||
// Unbind VAO (optional, but good practice)
|
||||
glBindVertexArray(0);
|
||||
}
|
||||
|
||||
void RenderWindow::RenderSceneToFBO()
|
||||
{
|
||||
// Spin
|
||||
m_RotationAngle += 0.5f;
|
||||
|
||||
m_FBO.Bind();
|
||||
glViewport(0, 0, m_LastWidth, m_LastHeight);
|
||||
|
||||
glEnable(GL_DEPTH_TEST);
|
||||
glClearColor(0.1f, 0.15f, 0.2f, 1.f);
|
||||
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
||||
|
||||
// Use our unlit shader
|
||||
m_Shader.Use();
|
||||
|
||||
// Build a MVP matrix with GLM (model * view * proj)
|
||||
// 1) Model: rotate around Y or diagonal axis
|
||||
glm::mat4 model = glm::mat4(1.0f);
|
||||
model = glm::rotate(model, glm::radians(m_RotationAngle), glm::vec3(1.0f, 1.0f, 0.0f));
|
||||
|
||||
// 2) View: move camera back by 5 on Z
|
||||
glm::mat4 view = glm::translate(glm::mat4(1.0f), glm::vec3(0.f, 0.f, -5.f));
|
||||
|
||||
// 3) Projection: perspective
|
||||
float aspect = (float)m_LastWidth / (float)m_LastHeight;
|
||||
glm::mat4 projection = glm::perspective(glm::radians(45.f), aspect, 0.1f, 100.f);
|
||||
|
||||
glm::mat4 mvp = projection * view * model;
|
||||
|
||||
// Upload MVP to the shader
|
||||
GLint mvpLoc = glGetUniformLocation(m_Shader.GetProgramID(), "uMVP");
|
||||
glUniformMatrix4fv(mvpLoc, 1, GL_FALSE, &mvp[0][0]);
|
||||
|
||||
// Draw the cube with our VAO
|
||||
glBindVertexArray(m_VAO);
|
||||
glDrawElements(GL_TRIANGLES, 36, GL_UNSIGNED_INT, 0);
|
||||
|
||||
glBindVertexArray(0);
|
||||
FBO::Unbind();
|
||||
}
|
28
src/Windows/RenderWindow.h
Normal file
28
src/Windows/RenderWindow.h
Normal file
@ -0,0 +1,28 @@
|
||||
#pragma once
|
||||
#include "../Rendering/FBO.h"
|
||||
#include "../Rendering/Shader.h"
|
||||
#include <glm/glm.hpp>
|
||||
|
||||
class RenderWindow
|
||||
{
|
||||
public:
|
||||
void Show(); // Called per-frame
|
||||
|
||||
private:
|
||||
void InitGLResources(); // Create VAO/VBO/EBO + load shader
|
||||
void RenderSceneToFBO(); // Renders the spinning cube with our unlit shader
|
||||
|
||||
FBO m_FBO;
|
||||
float m_RotationAngle = 0.f;
|
||||
int m_LastWidth = 0;
|
||||
int m_LastHeight = 0;
|
||||
|
||||
// VAO/VBO/EBO IDs
|
||||
unsigned int m_VAO = 0;
|
||||
unsigned int m_VBO = 0;
|
||||
unsigned int m_EBO = 0;
|
||||
|
||||
// Our unlit shader
|
||||
Shader m_Shader;
|
||||
bool m_Initialized = false;
|
||||
};
|
447
src/main.cpp
447
src/main.cpp
@ -1,450 +1,23 @@
|
||||
// src/main.cpp
|
||||
|
||||
#include <GLFW/glfw3.h>
|
||||
#include <cstdio>
|
||||
#include "Engine.h"
|
||||
|
||||
#include "imgui.h"
|
||||
#include "imgui_impl_glfw.h"
|
||||
#include "imgui_impl_opengl3.h"
|
||||
#include "../IconsFontAwesome6.h" // Ensure correct path
|
||||
|
||||
#include <iostream>
|
||||
#include <stdio.h>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
|
||||
#include "stb_image.h" // Include stb_image.h
|
||||
|
||||
#include "ECS.h" // Include the ECS header
|
||||
#include "Logger.h" // Include the Logger header
|
||||
#include "TextureManager.h" // Include the TextureManager header
|
||||
#include "UI.h" // Include the UI header
|
||||
#include "Meshes.h" // Include the Meshes header
|
||||
#include "ShaderComponent.h" // Include the ShaderComponent header
|
||||
#include "CameraSystem.h" // Include the CameraSystem header
|
||||
|
||||
#include <glm/glm.hpp>
|
||||
#include <glm/gtc/matrix_transform.hpp>
|
||||
#include <glm/gtc/type_ptr.hpp>
|
||||
|
||||
// =====================
|
||||
// Callback for GLFW errors
|
||||
// =====================
|
||||
|
||||
static void glfw_error_callback(int error, const char* description)
|
||||
int main()
|
||||
{
|
||||
fprintf(stderr, "GLFW Error %d: %s\n", error, description);
|
||||
}
|
||||
|
||||
// =====================
|
||||
// Global Variables for Camera Control
|
||||
// =====================
|
||||
|
||||
bool firstMouse = true;
|
||||
float lastX = 1280.0f / 2.0f;
|
||||
float lastY = 720.0f / 2.0f;
|
||||
bool mouseCaptured = true;
|
||||
|
||||
// =====================
|
||||
// Forward Declarations
|
||||
// =====================
|
||||
|
||||
void mouse_callback(GLFWwindow* window, double xpos, double ypos);
|
||||
void scroll_callback(GLFWwindow* window, double xoffset, double yoffset);
|
||||
|
||||
// =====================
|
||||
// Camera Entity ID
|
||||
// =====================
|
||||
|
||||
Entity cameraEntity = UINT32_MAX;
|
||||
|
||||
// =====================
|
||||
// Main Function
|
||||
// =====================
|
||||
|
||||
int main(int, char**)
|
||||
{
|
||||
// Setup Logger
|
||||
Logger::GetInstance().Log(LogLevel::INFO, "Loading Engine...");
|
||||
|
||||
// Setup GLFW error callback
|
||||
glfwSetErrorCallback(glfw_error_callback);
|
||||
|
||||
// Initialize GLFW
|
||||
if (!glfwInit())
|
||||
MyEngine engine;
|
||||
// Initialize the engine (creates GLFW window, sets up ImGui, etc.)
|
||||
if (!engine.Init(1280, 720, "Tesseract Engine"))
|
||||
{
|
||||
Logger::GetInstance().Log(LogLevel::ERROR, "Failed to initialize GLFW.");
|
||||
return -1;
|
||||
fprintf(stderr, "Failed to initialize engine.\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
// GL 3.3 + GLSL 330
|
||||
const char* glsl_version = "#version 330";
|
||||
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
|
||||
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
|
||||
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
|
||||
#ifdef __APPLE__
|
||||
glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE); // Required on Mac
|
||||
#endif
|
||||
|
||||
// Create window with graphics context
|
||||
GLFWwindow* window = glfwCreateWindow(1280, 720, "Tesseract Engine - 3D", NULL, NULL);
|
||||
if (window == NULL)
|
||||
{
|
||||
Logger::GetInstance().Log(LogLevel::ERROR, "Failed to create GLFW window.");
|
||||
glfwTerminate();
|
||||
return -1;
|
||||
}
|
||||
glfwMakeContextCurrent(window);
|
||||
glfwSwapInterval(1); // Enable vsync
|
||||
|
||||
// Set viewport
|
||||
int display_w, display_h;
|
||||
glfwGetFramebufferSize(window, &display_w, &display_h);
|
||||
glViewport(0, 0, display_w, display_h);
|
||||
|
||||
// Setup Dear ImGui context
|
||||
IMGUI_CHECKVERSION();
|
||||
ImGui::CreateContext();
|
||||
ImGuiIO& io = ImGui::GetIO(); (void)io;
|
||||
io.ConfigFlags |= ImGuiConfigFlags_DockingEnable; // Enable Docking
|
||||
// io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable; // Enable Multi-Viewport (optional)
|
||||
|
||||
// Load Fonts
|
||||
ImFontConfig fontConfig;
|
||||
fontConfig.MergeMode = true;
|
||||
fontConfig.PixelSnapH = true;
|
||||
|
||||
// Paths to your fonts
|
||||
const char* font_path = "./assets/fonts/Roboto-Medium.ttf"; // Replace with your default font
|
||||
const char* fa_font_path = "./assets/fonts/fa-solid-900.ttf"; // Replace with your Font Awesome font
|
||||
|
||||
// Load default font
|
||||
ImFont* default_font = io.Fonts->AddFontFromFileTTF(font_path, 16.0f);
|
||||
if (!default_font)
|
||||
{
|
||||
Logger::GetInstance().Log(LogLevel::ERROR, "Failed to load default font!");
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Define the Font Awesome icon range
|
||||
static const ImWchar icons_ranges[] = { ICON_MIN_FA, ICON_MAX_FA, 0 };
|
||||
|
||||
// Merge Font Awesome icons
|
||||
fontConfig.GlyphMinAdvanceX = 13.0f; // Adjust if necessary
|
||||
ImFont* fa_font = io.Fonts->AddFontFromFileTTF(fa_font_path, 16.0f, &fontConfig, icons_ranges);
|
||||
if (!fa_font)
|
||||
{
|
||||
Logger::GetInstance().Log(LogLevel::ERROR, "Failed to load Font Awesome font!");
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Build the font atlas
|
||||
io.Fonts->Build();
|
||||
|
||||
// Setup Dear ImGui style
|
||||
ImGui::StyleColorsDark();
|
||||
// ImGui::StyleColorsClassic(); // Alternative theme
|
||||
|
||||
// When viewports are enabled, tweak WindowRounding/WindowBg so platform windows can look identical to regular ones.
|
||||
/*
|
||||
ImGuiStyle& style = ImGui::GetStyle();
|
||||
if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable)
|
||||
{
|
||||
style.WindowRounding = 0.0f;
|
||||
style.Colors[ImGuiCol_WindowBg].w = 1.0f;
|
||||
}
|
||||
*/
|
||||
|
||||
// Setup Platform/Renderer backends
|
||||
ImGui_ImplGlfw_InitForOpenGL(window, true);
|
||||
ImGui_ImplOpenGL3_Init(glsl_version);
|
||||
|
||||
// Initialize ECS
|
||||
EntityManager entityManager;
|
||||
ComponentManager componentManager;
|
||||
entityManager.Init();
|
||||
componentManager.RegisterComponent<TransformComponent>();
|
||||
componentManager.RegisterComponent<MeshComponent>();
|
||||
componentManager.RegisterComponent<Shader>();
|
||||
componentManager.RegisterComponent<CameraComponent>();
|
||||
|
||||
// Create a default entity with TransformComponent, MeshComponent, Shader, and CameraComponent
|
||||
Entity defaultEntity = entityManager.CreateEntity();
|
||||
componentManager.AddComponent<TransformComponent>(defaultEntity, TransformComponent());
|
||||
componentManager.AddComponent<MeshComponent>(defaultEntity, CreateCubeMesh());
|
||||
Shader shader("shaders/basic.vert", "shaders/basic.frag");
|
||||
componentManager.AddComponent<Shader>(defaultEntity, shader);
|
||||
componentManager.AddComponent<CameraComponent>(defaultEntity, CameraComponent());
|
||||
|
||||
Logger::GetInstance().Log(LogLevel::INFO, "Engine initialized successfully.");
|
||||
|
||||
// Instantiate TextureManager
|
||||
TextureManager textureManager;
|
||||
|
||||
// Load Textures if necessary
|
||||
// GLuint diffuseMap = textureManager.LoadTexture("path_to_diffuse_map.png");
|
||||
// GLuint specularMap = textureManager.LoadTexture("path_to_specular_map.png");
|
||||
|
||||
// Setup Framebuffer Object (FBO) for rendering
|
||||
GLuint framebuffer;
|
||||
glGenFramebuffers(1, &framebuffer);
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);
|
||||
|
||||
// Create a color attachment texture
|
||||
GLuint texColorBuffer;
|
||||
glGenTextures(1, &texColorBuffer);
|
||||
glBindTexture(GL_TEXTURE_2D, texColorBuffer);
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, display_w, display_h, 0, GL_RGB, GL_UNSIGNED_BYTE, NULL);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
glBindTexture(GL_TEXTURE_2D, 0);
|
||||
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texColorBuffer, 0);
|
||||
|
||||
// Create a renderbuffer object for depth and stencil attachment
|
||||
GLuint rbo;
|
||||
glGenRenderbuffers(1, &rbo);
|
||||
glBindRenderbuffer(GL_RENDERBUFFER, rbo);
|
||||
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, display_w, display_h);
|
||||
glBindRenderbuffer(GL_RENDERBUFFER, 0);
|
||||
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER, rbo);
|
||||
|
||||
// Check if framebuffer is complete
|
||||
if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
|
||||
Logger::GetInstance().Log(LogLevel::ERROR, "ERROR::FRAMEBUFFER:: Framebuffer is not complete!");
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
||||
|
||||
// Setup Camera System
|
||||
float deltaTime = 0.0f; // Time between current frame and last frame
|
||||
float lastFrame = 0.0f; // Time of last frame
|
||||
CameraSystem cameraSystem(window, deltaTime);
|
||||
|
||||
// Setup Mouse Callbacks
|
||||
glfwSetCursorPosCallback(window, mouse_callback);
|
||||
glfwSetScrollCallback(window, scroll_callback);
|
||||
|
||||
// Capture the mouse cursor
|
||||
glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_DISABLED);
|
||||
|
||||
// Variables for Console
|
||||
bool show_console = true;
|
||||
|
||||
// Variable to track the selected entity
|
||||
Entity selectedEntity = defaultEntity;
|
||||
|
||||
// Main loop
|
||||
while (!glfwWindowShouldClose(window))
|
||||
{
|
||||
// Per-frame time logic
|
||||
float currentFrame = static_cast<float>(glfwGetTime());
|
||||
deltaTime = currentFrame - lastFrame;
|
||||
lastFrame = currentFrame;
|
||||
|
||||
// Poll and handle events (inputs, window resize, etc.)
|
||||
glfwPollEvents();
|
||||
|
||||
// Start the Dear ImGui frame
|
||||
ImGui_ImplOpenGL3_NewFrame();
|
||||
ImGui_ImplGlfw_NewFrame();
|
||||
ImGui::NewFrame();
|
||||
|
||||
// Bind to framebuffer and draw scene as we normally would to color texture
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);
|
||||
glEnable(GL_DEPTH_TEST); // Enable depth testing for 3D
|
||||
|
||||
// Clear buffers
|
||||
glClearColor(0.1f, 0.1f, 0.1f, 1.0f);
|
||||
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
||||
|
||||
// Use shader
|
||||
Shader& activeShader = componentManager.GetComponent<Shader>(defaultEntity);
|
||||
activeShader.Use();
|
||||
|
||||
// Retrieve camera view and projection matrices
|
||||
glm::mat4 view;
|
||||
glm::mat4 projection;
|
||||
glm::vec3 cameraPos;
|
||||
for(auto entity : entityManager.GetActiveEntities()) {
|
||||
if(componentManager.HasComponent<CameraComponent>(entity)) {
|
||||
auto& camera = componentManager.GetComponent<CameraComponent>(entity);
|
||||
view = camera.GetViewMatrix();
|
||||
cameraPos = camera.Position;
|
||||
}
|
||||
}
|
||||
|
||||
projection = glm::perspective(glm::radians(45.0f),
|
||||
(float)display_w / (float)display_h,
|
||||
0.1f, 100.0f);
|
||||
|
||||
// Set uniforms
|
||||
activeShader.SetMat4("view", view);
|
||||
activeShader.SetMat4("projection", projection);
|
||||
activeShader.SetVec3("viewPos", cameraPos);
|
||||
|
||||
// Set light properties
|
||||
activeShader.SetVec3("light.position", glm::vec3(1.2f, 1.0f, 2.0f));
|
||||
activeShader.SetVec3("light.ambient", glm::vec3(0.2f, 0.2f, 0.2f));
|
||||
activeShader.SetVec3("light.diffuse", glm::vec3(0.5f, 0.5f, 0.5f));
|
||||
activeShader.SetVec3("light.specular", glm::vec3(1.0f, 1.0f, 1.0f));
|
||||
|
||||
// Set material properties
|
||||
activeShader.SetInt("material.diffuse", 0);
|
||||
activeShader.SetInt("material.specular", 1);
|
||||
activeShader.SetFloat("material.shininess", 32.0f);
|
||||
|
||||
// Bind textures if any
|
||||
// For example:
|
||||
// glActiveTexture(GL_TEXTURE0);
|
||||
// glBindTexture(GL_TEXTURE_2D, diffuseMap);
|
||||
// glActiveTexture(GL_TEXTURE1);
|
||||
// glBindTexture(GL_TEXTURE_2D, specularMap);
|
||||
|
||||
// Render all meshes
|
||||
for(auto entity : entityManager.GetActiveEntities()) {
|
||||
if(componentManager.HasComponent<MeshComponent>(entity) && componentManager.HasComponent<TransformComponent>(entity)) {
|
||||
auto& mesh = componentManager.GetComponent<MeshComponent>(entity);
|
||||
auto& transform = componentManager.GetComponent<TransformComponent>(entity);
|
||||
|
||||
// Create model matrix
|
||||
glm::mat4 model = glm::mat4(1.0f);
|
||||
model = glm::translate(model, transform.position);
|
||||
model = glm::rotate(model, glm::radians(transform.rotation.x), glm::vec3(1.0f, 0.0f, 0.0f));
|
||||
model = glm::rotate(model, glm::radians(transform.rotation.y), glm::vec3(0.0f, 1.0f, 0.0f));
|
||||
model = glm::rotate(model, glm::radians(transform.rotation.z), glm::vec3(0.0f, 0.0f, 1.0f));
|
||||
model = glm::scale(model, transform.scale);
|
||||
|
||||
activeShader.SetMat4("model", model);
|
||||
|
||||
// Bind VAO and draw
|
||||
glBindVertexArray(mesh.VAO);
|
||||
glDrawElements(GL_TRIANGLES, static_cast<GLsizei>(mesh.indices.size()), GL_UNSIGNED_INT, 0);
|
||||
glBindVertexArray(0);
|
||||
}
|
||||
}
|
||||
|
||||
// Unbind framebuffer
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
||||
|
||||
// Disable depth testing for UI rendering
|
||||
glDisable(GL_DEPTH_TEST);
|
||||
|
||||
// Start ImGui frame
|
||||
ImGui::NewFrame();
|
||||
|
||||
// Create DockSpace
|
||||
ImGuiWindowFlags dockspace_flags = ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoCollapse |
|
||||
ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoMove |
|
||||
ImGuiWindowFlags_NoBringToFrontOnFocus | ImGuiWindowFlags_NoNavFocus;
|
||||
const ImGuiViewport* viewport_main = ImGui::GetMainViewport();
|
||||
|
||||
ImGui::SetNextWindowPos(ImVec2(viewport_main->Pos.x, viewport_main->Pos.y));
|
||||
ImGui::SetNextWindowSize(ImVec2(viewport_main->Size.x, viewport_main->Size.y));
|
||||
ImGui::SetNextWindowViewport(viewport_main->ID);
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_WindowRounding, 0.0f);
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_WindowBorderSize, 0.0f);
|
||||
ImGui::Begin("DockSpaceWindow", nullptr, dockspace_flags);
|
||||
ImGui::PopStyleVar(2);
|
||||
|
||||
// DockSpace
|
||||
if (io.ConfigFlags & ImGuiConfigFlags_DockingEnable)
|
||||
{
|
||||
ImGuiID dockspace_id = ImGui::GetID("MyDockSpace");
|
||||
ImGui::DockSpace(dockspace_id, ImVec2(0.0f, 0.0f), ImGuiDockNodeFlags_None);
|
||||
}
|
||||
|
||||
ImGui::End();
|
||||
|
||||
// Show GUI windows
|
||||
ShowMainMenuBar();
|
||||
ShowConsole(&show_console);
|
||||
ShowEntityTree(entityManager, componentManager, selectedEntity);
|
||||
ShowInspector(componentManager, selectedEntity);
|
||||
|
||||
// Render the framebuffer texture in the Viewport panel
|
||||
ImGui::Begin("Viewport");
|
||||
ImGui::Text("3D Viewport");
|
||||
ImGui::Image((void*)(intptr_t)texColorBuffer, ImVec2(1280, 720), ImVec2(0,1), ImVec2(1,0));
|
||||
ImGui::End();
|
||||
|
||||
// Rendering
|
||||
ImGui::Render();
|
||||
glfwGetFramebufferSize(window, &display_w, &display_h);
|
||||
glViewport(0, 0, display_w, display_h);
|
||||
glClearColor(0.1f, 0.1f, 0.1f, 1.0f); // Dark background
|
||||
glClear(GL_COLOR_BUFFER_BIT);
|
||||
ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData());
|
||||
|
||||
// Update and Render additional Platform Windows (for multi-viewport)
|
||||
/*
|
||||
if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable)
|
||||
{
|
||||
GLFWwindow* backup_current_context = glfwGetCurrentContext();
|
||||
ImGui::UpdatePlatformWindows();
|
||||
ImGui::RenderPlatformWindowsDefault();
|
||||
glfwMakeContextCurrent(backup_current_context);
|
||||
}
|
||||
*/
|
||||
|
||||
glfwSwapBuffers(window);
|
||||
|
||||
// Process camera input
|
||||
cameraSystem.ProcessInput(entityManager, componentManager);
|
||||
}
|
||||
|
||||
// Cleanup framebuffer objects
|
||||
glDeleteFramebuffers(1, &framebuffer);
|
||||
glDeleteTextures(1, &texColorBuffer);
|
||||
glDeleteRenderbuffers(1, &rbo);
|
||||
engine.Run();
|
||||
|
||||
// Cleanup
|
||||
textureManager.Cleanup();
|
||||
ImGui_ImplOpenGL3_Shutdown();
|
||||
ImGui_ImplGlfw_Shutdown();
|
||||
ImGui::DestroyContext();
|
||||
|
||||
glfwDestroyWindow(window);
|
||||
glfwTerminate();
|
||||
engine.Cleanup();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// =====================
|
||||
// Mouse Movement Callback
|
||||
// =====================
|
||||
|
||||
void mouse_callback(GLFWwindow* window, double xpos, double ypos)
|
||||
{
|
||||
if (cameraEntity == UINT32_MAX)
|
||||
return;
|
||||
|
||||
auto& camera = EntityManager::GetInstance().GetComponent<CameraComponent>(cameraEntity); // Assuming GetInstance exists
|
||||
if (!cameraEntity) return;
|
||||
|
||||
if (firstMouse)
|
||||
{
|
||||
lastX = static_cast<float>(xpos);
|
||||
lastY = static_cast<float>(ypos);
|
||||
firstMouse = false;
|
||||
}
|
||||
|
||||
float xoffset = static_cast<float>(xpos) - lastX;
|
||||
float yoffset = lastY - static_cast<float>(ypos); // Reversed since y-coordinates go from bottom to top
|
||||
|
||||
lastX = static_cast<float>(xpos);
|
||||
lastY = static_cast<float>(ypos);
|
||||
|
||||
camera.ProcessMouseMovement(xoffset, yoffset);
|
||||
}
|
||||
|
||||
// =====================
|
||||
// Scroll Callback
|
||||
// =====================
|
||||
|
||||
void scroll_callback(GLFWwindow* window, double xoffset, double yoffset)
|
||||
{
|
||||
if (cameraEntity == UINT32_MAX)
|
||||
return;
|
||||
|
||||
auto& camera = EntityManager::GetInstance().GetComponent<CameraComponent>(cameraEntity); // Assuming GetInstance exists
|
||||
if (!cameraEntity) return;
|
||||
|
||||
camera.ProcessMouseScroll(static_cast<float>(yoffset));
|
||||
}
|
||||
|
455
vendor/gcml/gcml.h
vendored
Normal file
455
vendor/gcml/gcml.h
vendored
Normal file
@ -0,0 +1,455 @@
|
||||
#ifndef GCML_H
|
||||
#define GCML_H
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
// -------------------------
|
||||
// General Utility Macros
|
||||
// -------------------------
|
||||
|
||||
/**
|
||||
* @brief Returns the minimum of two values.
|
||||
*/
|
||||
#define MIN(a, b) (( (a) < (b) ) ? (a) : (b))
|
||||
|
||||
/**
|
||||
* @brief Returns the maximum of two values.
|
||||
*/
|
||||
#define MAX(a, b) (( (a) > (b) ) ? (a) : (b))
|
||||
|
||||
/**
|
||||
* @brief Calculates the number of elements in an array.
|
||||
*/
|
||||
#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
|
||||
|
||||
/**
|
||||
* @brief Suppresses compiler warnings for unused variables.
|
||||
*/
|
||||
#define UNUSED(x) (void)(x)
|
||||
|
||||
/**
|
||||
* @brief Aligns a value `x` up to the nearest multiple of `align`.
|
||||
*/
|
||||
#define ALIGN_UP(x, align) (((x) + ((align)-1)) & ~((align)-1))
|
||||
|
||||
/**
|
||||
* @brief Aligns a value `x` down to the nearest multiple of `align`.
|
||||
*/
|
||||
#define ALIGN_DOWN(x, align) ((x) & ~((align)-1))
|
||||
|
||||
// -------------------------
|
||||
// Debugging and Logging Macros
|
||||
// -------------------------
|
||||
|
||||
#ifdef DEBUG
|
||||
/**
|
||||
* @brief Prints debug messages with file name, line number, and function name.
|
||||
*/
|
||||
#define DEBUG_PRINT(fmt, ...) \
|
||||
fprintf(stderr, "DEBUG: %s:%d:%s(): " fmt "\n", \
|
||||
__FILE__, __LINE__, __func__, ##__VA_ARGS__)
|
||||
#else
|
||||
#define DEBUG_PRINT(fmt, ...) // No operation in release builds
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Logs informational messages.
|
||||
*/
|
||||
#define LOG_INFO(fmt, ...) \
|
||||
fprintf(stdout, "INFO: " fmt "\n", ##__VA_ARGS__)
|
||||
|
||||
/**
|
||||
* @brief Logs warning messages.
|
||||
*/
|
||||
#define LOG_WARN(fmt, ...) \
|
||||
fprintf(stderr, "WARNING: " fmt "\n", ##__VA_ARGS__)
|
||||
|
||||
/**
|
||||
* @brief Logs error messages.
|
||||
*/
|
||||
#define LOG_ERROR(fmt, ...) \
|
||||
fprintf(stderr, "ERROR: " fmt "\n", ##__VA_ARGS__)
|
||||
|
||||
/**
|
||||
* @brief Logs fatal error messages and exits the program.
|
||||
*/
|
||||
#define LOG_FATAL(fmt, ...) do { \
|
||||
fprintf(stderr, "FATAL: " fmt "\n", ##__VA_ARGS__); \
|
||||
exit(EXIT_FAILURE); \
|
||||
} while (0)
|
||||
|
||||
// -------------------------
|
||||
// Assertion Macros
|
||||
// -------------------------
|
||||
|
||||
/**
|
||||
* @brief Asserts a condition and logs an error message if the condition is false.
|
||||
*/
|
||||
#ifndef NDEBUG
|
||||
#define ASSERT(cond, fmt, ...) do { \
|
||||
if (!(cond)) { \
|
||||
fprintf(stderr, "Assertion failed: (%s), function %s, file %s, line %d.\n", \
|
||||
#cond, __func__, __FILE__, __LINE__); \
|
||||
fprintf(stderr, fmt "\n", ##__VA_ARGS__); \
|
||||
abort(); \
|
||||
} \
|
||||
} while (0)
|
||||
#else
|
||||
#define ASSERT(cond, fmt, ...) ((void)0)
|
||||
#endif
|
||||
|
||||
// -------------------------
|
||||
// Stringification Macros
|
||||
// -------------------------
|
||||
|
||||
/**
|
||||
* @brief Converts a macro argument to a string.
|
||||
*/
|
||||
#define STRINGIFY(x) #x
|
||||
#define TOSTRING(x) STRINGIFY(x)
|
||||
|
||||
// -------------------------
|
||||
// Token Pasting Macros
|
||||
// -------------------------
|
||||
|
||||
/**
|
||||
* @brief Concatenates two tokens.
|
||||
*/
|
||||
#define CONCAT(a, b) a ## b
|
||||
|
||||
/**
|
||||
* @brief Concatenates three tokens.
|
||||
*/
|
||||
#define CONCAT3(a, b, c) a ## b ## c
|
||||
|
||||
// -------------------------
|
||||
// Memory Management Macros
|
||||
// -------------------------
|
||||
|
||||
/**
|
||||
* @brief Allocates memory and checks for allocation failure.
|
||||
* @param ptr The pointer to assign the allocated memory.
|
||||
* @param size The size in bytes to allocate.
|
||||
*/
|
||||
#define SAFE_MALLOC(ptr, size) do { \
|
||||
(ptr) = malloc(size); \
|
||||
if ((ptr) == NULL) { \
|
||||
LOG_FATAL("Memory allocation failed for size %zu", (size_t)(size)); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
/**
|
||||
* @brief Allocates zero-initialized memory and checks for allocation failure.
|
||||
* @param ptr The pointer to assign the allocated memory.
|
||||
* @param count The number of elements to allocate.
|
||||
* @param type The type of each element.
|
||||
*/
|
||||
#define SAFE_CALLOC(ptr, count, type) do { \
|
||||
(ptr) = calloc((count), sizeof(type)); \
|
||||
if ((ptr) == NULL) { \
|
||||
LOG_FATAL("Memory allocation (calloc) failed for count %zu of type %s", \
|
||||
(size_t)(count), #type); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
/**
|
||||
* @brief Frees memory and sets the pointer to NULL.
|
||||
* @param ptr The pointer to free.
|
||||
*/
|
||||
#define SAFE_FREE(ptr) do { \
|
||||
free(ptr); \
|
||||
ptr = NULL; \
|
||||
} while(0)
|
||||
|
||||
// -------------------------
|
||||
// Type Casting Macros
|
||||
// -------------------------
|
||||
|
||||
/**
|
||||
* @brief Safely casts a pointer to a specific type.
|
||||
* @param ptr The pointer to cast.
|
||||
* @param type The target type.
|
||||
*/
|
||||
#define SAFE_CAST(ptr, type) ((type)(ptr))
|
||||
|
||||
// -------------------------
|
||||
// Bit Manipulation Macros
|
||||
// -------------------------
|
||||
|
||||
/**
|
||||
* @brief Sets a bit at a specific position.
|
||||
* @param x The variable.
|
||||
* @param pos The bit position.
|
||||
*/
|
||||
#define SET_BIT(x, pos) ((x) |= (1U << (pos)))
|
||||
|
||||
/**
|
||||
* @brief Clears a bit at a specific position.
|
||||
* @param x The variable.
|
||||
* @param pos The bit position.
|
||||
*/
|
||||
#define CLEAR_BIT(x, pos) ((x) &= ~(1U << (pos)))
|
||||
|
||||
/**
|
||||
* @brief Toggles a bit at a specific position.
|
||||
* @param x The variable.
|
||||
* @param pos The bit position.
|
||||
*/
|
||||
#define TOGGLE_BIT(x, pos) ((x) ^= (1U << (pos)))
|
||||
|
||||
/**
|
||||
* @brief Checks if a bit at a specific position is set.
|
||||
* @param x The variable.
|
||||
* @param pos The bit position.
|
||||
* @return Non-zero if the bit is set, zero otherwise.
|
||||
*/
|
||||
#define CHECK_BIT(x, pos) (((x) >> (pos)) & 1U)
|
||||
|
||||
// -------------------------
|
||||
// Compile-Time Assertion Macro
|
||||
// -------------------------
|
||||
|
||||
/**
|
||||
* @brief Performs a compile-time assertion.
|
||||
* @param expr The expression to evaluate.
|
||||
* @param msg The message to display if the assertion fails.
|
||||
*/
|
||||
#define STATIC_ASSERT(expr, msg) _Static_assert(expr, msg)
|
||||
|
||||
// -------------------------
|
||||
// Deprecation Warning Macros
|
||||
// -------------------------
|
||||
|
||||
/**
|
||||
* @brief Marks a function as deprecated with a custom message.
|
||||
*/
|
||||
#if defined(__GNUC__) || defined(__clang__)
|
||||
#define DEPRECATED(msg) __attribute__((deprecated(msg)))
|
||||
#elif defined(_MSC_VER)
|
||||
#define DEPRECATED(msg) __declspec(deprecated(msg))
|
||||
#else
|
||||
#pragma message("WARNING: DEPRECATED macro is not supported for this compiler.")
|
||||
#define DEPRECATED(msg)
|
||||
#endif
|
||||
|
||||
// -------------------------
|
||||
// Loop Macros
|
||||
// -------------------------
|
||||
|
||||
/**
|
||||
* @brief Iterates over each element in an array.
|
||||
* @param item The loop variable.
|
||||
* @param array The array to iterate over.
|
||||
*/
|
||||
#define FOREACH(item, array) \
|
||||
for (size_t keep = 1, \
|
||||
count = ARRAY_SIZE(array), \
|
||||
i = 0; \
|
||||
keep && i < count; \
|
||||
keep = !keep, i++) \
|
||||
for (item = (array) + i; keep; keep = !keep)
|
||||
|
||||
/**
|
||||
* @brief Repeats a block of code `n` times.
|
||||
* @param n The number of times to repeat.
|
||||
* @param block The block of code to execute.
|
||||
*/
|
||||
#define REPEAT(n, block) \
|
||||
for (size_t _i = 0; _i < (n); ++_i) { block; }
|
||||
|
||||
// -------------------------
|
||||
// Swap Macro
|
||||
// -------------------------
|
||||
|
||||
/**
|
||||
* @brief Swaps two variables of the same type.
|
||||
* @param a The first variable.
|
||||
* @param b The second variable.
|
||||
*/
|
||||
#define SWAP(a, b) do { \
|
||||
typeof(a) _swap_temp = (a); \
|
||||
(a) = (b); \
|
||||
(b) = _swap_temp; \
|
||||
} while (0)
|
||||
|
||||
// -------------------------
|
||||
// Execute Once Macro
|
||||
// -------------------------
|
||||
|
||||
/**
|
||||
* @brief Executes a block of code only once.
|
||||
* @param block The block of code to execute.
|
||||
*/
|
||||
#define DO_ONCE(block) \
|
||||
do { \
|
||||
static int _do_once_flag = 0; \
|
||||
if (!_do_once_flag) { \
|
||||
_do_once_flag = 1; \
|
||||
block \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
// -------------------------
|
||||
// Utility Macros
|
||||
// -------------------------
|
||||
|
||||
/**
|
||||
* @brief Calculates the offset of a member within a struct.
|
||||
* @param type The struct type.
|
||||
* @param member The member within the struct.
|
||||
*/
|
||||
#define OFFSET_OF(type, member) ((size_t) &(((type *)0)->member))
|
||||
|
||||
/**
|
||||
* @brief Retrieves the containing struct from a member pointer.
|
||||
* @param ptr The pointer to the member.
|
||||
* @param type The type of the containing struct.
|
||||
* @param member The member within the struct.
|
||||
*/
|
||||
#define CONTAINER_OF(ptr, type, member) \
|
||||
((type *)((char *)(ptr) - OFFSET_OF(type, member)))
|
||||
|
||||
|
||||
// -------------------------
|
||||
// Additional Utility Macros
|
||||
// -------------------------
|
||||
|
||||
/**
|
||||
* @brief Safely reallocates memory and checks for allocation failure.
|
||||
* @param ptr The pointer to the previously allocated memory.
|
||||
* @param size The new size in bytes to allocate.
|
||||
*/
|
||||
#define SAFE_REALLOC(ptr, size) do { \
|
||||
void* _tmp = realloc((ptr), (size)); \
|
||||
if ((_tmp) == NULL) { \
|
||||
LOG_FATAL("Memory reallocation failed for size %zu", (size_t)(size)); \
|
||||
} else { \
|
||||
(ptr) = _tmp; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
/**
|
||||
* @brief Marks a function as unused to suppress compiler warnings.
|
||||
*/
|
||||
#define UNUSED_FUNCTION __attribute__((unused))
|
||||
|
||||
/**
|
||||
* @brief Converts a value to a string at compile time.
|
||||
* @param value The value to stringify.
|
||||
* @return The string representation of the value.
|
||||
*/
|
||||
#define TO_STRING(value) TOSTRING(value)
|
||||
|
||||
/**
|
||||
* @brief Generates a unique identifier by appending the line number.
|
||||
* @param prefix The prefix for the identifier.
|
||||
* @return A unique identifier.
|
||||
*/
|
||||
#define UNIQUE_ID(prefix) CONCAT(prefix, __LINE__)
|
||||
|
||||
/**
|
||||
* @brief Forces a value to evaluate to a specific type without altering its binary representation.
|
||||
* @param value The value to cast.
|
||||
* @param type The target type.
|
||||
* @return The value cast to the specified type.
|
||||
*/
|
||||
#define FORCE_CAST(value, type) (*(type*)&(value))
|
||||
|
||||
/**
|
||||
* @brief Creates a do-while loop that executes exactly once.
|
||||
* @param block The block of code to execute.
|
||||
*/
|
||||
#define EXECUTE_ONCE(block) do { block } while(0)
|
||||
|
||||
/**
|
||||
* @brief Checks if a pointer is aligned to a specified boundary.
|
||||
* @param ptr The pointer to check.
|
||||
* @param align The alignment boundary (must be a power of two).
|
||||
* @return Non-zero if aligned, zero otherwise.
|
||||
*/
|
||||
#define IS_ALIGNED(ptr, align) ((((uintptr_t)(const void*)(ptr)) & ((align) - 1)) == 0)
|
||||
|
||||
/**
|
||||
* @brief Calculates the number of bits set to 1 in a variable.
|
||||
* @param x The variable to count bits in.
|
||||
* @return The number of bits set to 1.
|
||||
*/
|
||||
#define COUNT_SET_BITS(x) (__builtin_popcount(x))
|
||||
|
||||
/**
|
||||
* @brief Calculates the ceiling of a division between two integers.
|
||||
* @param numerator The numerator.
|
||||
* @param denominator The denominator.
|
||||
* @return The ceiling of the division.
|
||||
*/
|
||||
#define CEIL_DIV(numerator, denominator) (((numerator) + (denominator) - 1) / (denominator))
|
||||
|
||||
/**
|
||||
* @brief Concatenates two tokens with an underscore.
|
||||
* @param a The first token.
|
||||
* @param b The second token.
|
||||
* @return The concatenated token separated by an underscore.
|
||||
*/
|
||||
#define CONCAT_WITH_UNDERSCORE(a, b) CONCAT(a, _##b)
|
||||
|
||||
/**
|
||||
* @brief Swaps two variables without using a temporary variable (only for integer types).
|
||||
* @param a The first variable.
|
||||
* @param b The second variable.
|
||||
*/
|
||||
#define SWAP_INPLACE(a, b) do { \
|
||||
(a) ^= (b); \
|
||||
(b) ^= (a); \
|
||||
(a) ^= (b); \
|
||||
} while (0)
|
||||
|
||||
// -------------------------
|
||||
// Safe Reallocation Macro
|
||||
// -------------------------
|
||||
|
||||
/**
|
||||
* @brief Safely reallocates memory and checks for allocation failure.
|
||||
* @param ptr The pointer to the previously allocated memory.
|
||||
* @param size The new size in bytes to allocate.
|
||||
*/
|
||||
#define SAFE_REALLOC(ptr, size) do { \
|
||||
void* _tmp = realloc((ptr), (size)); \
|
||||
if ((_tmp) == NULL) { \
|
||||
LOG_FATAL("Memory reallocation failed for size %zu", (size_t)(size)); \
|
||||
} else { \
|
||||
(ptr) = _tmp; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#define MAX_OF(...) MAX_OF_IMPL(__VA_ARGS__, MAX_OF_RSEQ_N())
|
||||
#define MAX_OF_IMPL(...) MAX_OF_ARG_N(__VA_ARGS__)
|
||||
#define MAX_OF_ARG_N(_1, _2, _3, _4, _5, N, ...) N
|
||||
#define MAX_OF_RSEQ_N() 5,4,3,2,1,0
|
||||
|
||||
#define MIN_OF(...) MIN_OF_IMPL(__VA_ARGS__, MIN_OF_RSEQ_N())
|
||||
#define MIN_OF_IMPL(...) MIN_OF_ARG_N(__VA_ARGS__)
|
||||
#define MIN_OF_ARG_N(_1, _2, _3, _4, _5, N, ...) N
|
||||
#define MIN_OF_RSEQ_N() 5,4,3,2,1,0
|
||||
|
||||
|
||||
#define ZERO_STRUCT(s) memset(&(s), 0, sizeof(s))
|
||||
|
||||
|
||||
#define PRINT_VAR(var) LOG_INFO(#var " = %d", var)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#endif // GCML_H
|
||||
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user