Merge branch 'Dev'

This commit is contained in:
OusmBlueNinja 2024-12-25 19:05:38 -06:00
commit 037561d2a5
49 changed files with 2293 additions and 405 deletions

View File

@ -2,38 +2,48 @@
# Compiler and Flags
CXX := g++
CXXFLAGS := -Wall -Wextra -std=c++17
CXXFLAGS := -Wall -Wextra -std=c++17 -g
# 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
INCLUDE_DIRS := $(SRC_DIR) $(VENDOR_DIRS) $(GLFW_INCLUDE) vendor/gcml
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 +62,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 +71,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)"

14
README.md Normal file
View File

@ -0,0 +1,14 @@
# Tesseract-Engine
A 3D Game engine for Small to Medium-sized games with a LUA Scripting interface. written in C++ with a simple, Good looking interface.
## Screen Shots
### Note: These screenshots are sorted by version.
#### 0.0.23
![](./assets/images/SS-Dev1_1.png)
#### 0.0.15
![](./assets/images/SS-Dev1_0.png)

BIN
assets/images/SS-Dev1_0.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 64 KiB

BIN
assets/images/SS-Dev1_1.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 198 KiB

View 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 * texColor;
}

View 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);
}

BIN
assets/textures/default.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 138 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

BIN
assets/textures/wood.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 765 KiB

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -1,46 +0,0 @@
[Window][DockSpace Demo]
Size=1280,720
Collapsed=0
[Window][Debug##Default]
Pos=60,60
Size=400,400
Collapsed=0
[Window][Hello, world!]
Pos=642,30
Size=630,682
Collapsed=0
DockId=0x00000002,0
[Window][Hello, world!]
Pos=8,30
Size=1264,682
Collapsed=0
DockId=0x00000001,0
[Window][DockSpace]
Pos=0,0
Size=1280,720
Collapsed=0
[Window][Viewport]
Pos=8,8
Size=1264,352
Collapsed=0
DockId=0x00000003,0
[Window][Console]
Pos=8,362
Size=1264,350
Collapsed=0
DockId=0x00000004,0
[Docking][Data]
DockSpace ID=0x14621557 Window=0x3DA2F1DE Pos=8,8 Size=1264,704 Split=Y Selected=0xC450F867
DockNode ID=0x00000003 Parent=0x14621557 SizeRef=1264,352 CentralNode=1 Selected=0xC450F867
DockNode ID=0x00000004 Parent=0x14621557 SizeRef=1264,350 Selected=0xEA83D666
DockSpace ID=0xC0DFADC4 Pos=8,30 Size=1264,682 Split=X Selected=0x1FC7AC8C
DockNode ID=0x00000001 Parent=0xC0DFADC4 SizeRef=632,685 CentralNode=1 Selected=0xAAD7FFD4
DockNode ID=0x00000002 Parent=0xC0DFADC4 SizeRef=630,685 Selected=0x1FC7AC8C

View File

@ -0,0 +1,15 @@
// src/Components/GameObject.h
#pragma once
#include <string>
#include "Transform.h"
#include "Mesh.h"
struct GameObject
{
std::string name; // Unique name for the GameObject
Transform transform; // Position, Rotation, Scale
Mesh mesh; // Rendering Mesh
// Add other components as needed
};

12
src/Componenets/Mesh.h Normal file
View File

@ -0,0 +1,12 @@
// Mesh.h
#pragma once
#include <GL/glew.h>
// A simple mesh storing a VAO, index count, and texture ID
struct Mesh
{
GLuint vao = 0; // Vertex Array Object
GLuint indexCount = 0; // Number of indices to draw
GLuint textureID = 0; // The texture handle
};

View File

@ -0,0 +1,14 @@
// Transform.h
#pragma once
#include <glm/glm.hpp>
// A simple transform with position, rotation, scale
struct Transform
{
glm::vec3 position {0.f, 0.f, 0.f};
glm::vec3 rotation {0.f, 0.f, 0.f}; // Euler angles, in degrees or radians
glm::vec3 scale {1.f, 1.f, 1.f};
};

389
src/Engine.cpp Normal file
View File

@ -0,0 +1,389 @@
// src/Engine.cpp
// Settings
#define VSync 0
#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"
#include "Windows/InspectorWindow.h"
AssetManager g_AssetManager;
LoggerWindow *g_LoggerWindow;
std::vector<GameObject> m_GameObjects;
bool MyEngine::Init(int width, int height, const std::string& title)
{
DEBUG_PRINT("[START] Engine Init");
// ------------------------------------------
// 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(VSync); // 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>();
m_InspectorWindow = std::make_unique<InspectorWindow>();
// Some initial logs
m_LoggerWindow->AddLog("Engine initialized.");
m_LoggerWindow->AddLog("Welcome to Tesseract Engine!");
g_LoggerWindow = m_LoggerWindow.get();
m_Running = true;
m_LastTime = glfwGetTime();
DEBUG_PRINT("[OK] Engine Init ");
return true;
}
GLuint CreateCubeVAO()
{
// Define cube vertices (Position + UVs)
static float g_CubeVertices[] =
{
// Front face
-1.f, -1.f, 1.f, 0.f, 0.f,
1.f, -1.f, 1.f, 1.f, 0.f,
1.f, 1.f, 1.f, 1.f, 1.f,
-1.f, 1.f, 1.f, 0.f, 1.f,
// Back face
-1.f, -1.f, -1.f, 1.f, 0.f,
1.f, -1.f, -1.f, 0.f, 0.f,
1.f, 1.f, -1.f, 0.f, 1.f,
-1.f, 1.f, -1.f, 1.f, 1.f,
// Left face
-1.f, -1.f, -1.f, 0.f, 0.f,
-1.f, -1.f, 1.f, 1.f, 0.f,
-1.f, 1.f, 1.f, 1.f, 1.f,
-1.f, 1.f, -1.f, 0.f, 1.f,
// Right face
1.f, -1.f, -1.f, 1.f, 0.f,
1.f, -1.f, 1.f, 0.f, 0.f,
1.f, 1.f, 1.f, 0.f, 1.f,
1.f, 1.f, -1.f, 1.f, 1.f,
// Top face
-1.f, 1.f, -1.f, 0.f, 0.f,
1.f, 1.f, -1.f, 1.f, 0.f,
1.f, 1.f, 1.f, 1.f, 1.f,
-1.f, 1.f, 1.f, 0.f, 1.f,
// Bottom face
-1.f, -1.f, -1.f, 1.f, 0.f,
1.f, -1.f, -1.f, 0.f, 0.f,
1.f, -1.f, 1.f, 0.f, 1.f,
-1.f, -1.f, 1.f, 1.f, 1.f,
};
// Define cube indices
static unsigned int g_CubeIndices[] =
{
// Front face
0, 1, 2, 2, 3, 0,
// Back face
4, 5, 6, 6, 7, 4,
// Left face
8, 9, 10, 10, 11, 8,
// Right face
12, 13, 14, 14, 15, 12,
// Top face
16, 17, 18, 18, 19, 16,
// Bottom face
20, 21, 22, 22, 23, 20
};
GLuint VAO, VBO, EBO;
// Generate and bind VAO
glGenVertexArrays(1, &VAO);
glBindVertexArray(VAO);
// Generate and bind VBO
glGenBuffers(1, &VBO);
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(g_CubeVertices), g_CubeVertices, GL_STATIC_DRAW);
// Generate and bind EBO
glGenBuffers(1, &EBO);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(g_CubeIndices), g_CubeIndices, GL_STATIC_DRAW);
// Define vertex attributes
// Position attribute (location = 0)
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE,
5 * sizeof(float), (void*)0);
glEnableVertexAttribArray(0);
// UV attribute (location = 1)
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE,
5 * sizeof(float), (void*)(3 * sizeof(float)));
glEnableVertexAttribArray(1);
// Unbind VAO (not EBO!)
glBindVertexArray(0);
// Optionally, unbind VBO and EBO for cleanliness
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
// Debug: Print VAO ID
printf("[MeshUtils] Initialized CubeVAO with ID: %u\n", VAO);
return VAO;
}
void MyEngine::Run()
{
DEBUG_PRINT("[START] Engine Run ");
// Pseudocode:
GameObject cube;
cube.transform.position = glm::vec3(0.f, 0.f, 0.f);
cube.transform.rotation = glm::vec3(0.f, 0.5f, 0.f);
cube.transform.scale = glm::vec3(1.f, 1.f, 1.f);
// Suppose we loaded a VAO, an EBO with 36 indices for the cube,
// and a texture ID from the asset manager
cube.mesh.vao = CreateCubeVAO();
cube.mesh.indexCount = 36;
cube.mesh.textureID = static_cast<GLuint>(reinterpret_cast<uintptr_t>(g_AssetManager.loadAsset(AssetType::TEXTURE, "assets/textures/wood.png")));
m_GameObjects.push_back(cube);
// Possibly create more GameObjects with different positions or textures
while (!glfwWindowShouldClose(m_Window) && m_Running)
{
// Poll
glfwPollEvents();
// Calculate FPS
double current_time = glfwGetTime();
double delta = current_time - m_LastTime;
m_FrameCount++;
if (delta >= 0.1)
{
m_Fps = (float)(m_FrameCount / delta);
m_Ms = 100.0f / m_Fps;
m_FrameCount = 0;
m_LastTime = current_time;
}
// Start new frame
BeginFrame();
// Show main DockSpace
ShowDockSpace();
m_InspectorWindow->Show();
// 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
// After rendering
m_PerformanceWindow->UpdatePerformanceStats(-1, -1);
// End frame
EndFrame();
}
DEBUG_PRINT("[OK] Engine Run ");
}
void MyEngine::Cleanup()
{
DEBUG_PRINT("[START] Engine 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;
DEBUG_PRINT("[OK] Engine Cleanup ");
}
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();
}

60
src/Engine.h Normal file
View File

@ -0,0 +1,60 @@
// src/Engine.h
#pragma once
#include <string>
#include <memory>
#include "Windows/RenderWindow.h"
#include "Windows/PerformanceWindow.h"
#include "Windows/LoggerWindow.h"
#include "Engine/AssetManager.h"
#include "Windows/InspectorWindow.h"
#include "Componenets/GameObject.h"
#include "Componenets/Mesh.h"
#include "Componenets/Transform.h"
#include "TestModel.h"
//#define DEBUG
#include "gcml.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;
std::unique_ptr<InspectorWindow> m_InspectorWindow;
// For FPS calculation
float m_Fps = 0.0f;
float m_Ms = 0.0f;
double m_LastTime = 0.0;
int m_FrameCount = 0;
};

147
src/Engine/AssetManager.cpp Normal file
View File

@ -0,0 +1,147 @@
#include "Engine/AssetManager.h"
#include <iostream>
// Include your Shader class
#include "Rendering/Shader.h"
#include "Windows/LoggerWindow.h"
// Include OpenGL loader (GLEW) for texture creation
#include <GL/glew.h>
// For texture loading
#define STB_IMAGE_IMPLEMENTATION
#include "stb/stb_image.h"
int LoaddedAssets = 0;
extern LoggerWindow *g_LoggerWindow;
void* AssetManager::loadAsset(AssetType type, const std::string& path)
{
// 1) Create a unique key for cache lookup
std::string key = generateKey(type, path);
// 2) Check if its already loaded
auto it = m_AssetMap.find(key);
if (it != m_AssetMap.end())
{
// Return existing pointer
return it->second.data;
}
// 3) Not loaded yet, load from disk
void* assetData = loadAssetFromDisk(type, path);
if (!assetData)
{
std::cerr << "[AssetManager] Failed to load asset: " << path << std::endl;
return nullptr;
}
// 4) Store in cache
GenericAsset newAsset;
newAsset.data = assetData;
m_AssetMap[key] = newAsset;
LoaddedAssets += 1;
g_LoggerWindow->AddLog("Loadded Asset: %s", path.c_str());
// 5) Return pointer
return assetData;
}
std::string AssetManager::generateKey(AssetType type, const std::string& path)
{
return std::to_string(static_cast<int>(type)) + ":" + path;
}
void* AssetManager::loadAssetFromDisk(AssetType type, const std::string& path)
{
switch (type)
{
case AssetType::TEXTURE:
{
// --------------------------------------------
// Load a texture with stb_image
// --------------------------------------------
std::cout << "[AssetManager] Loading TEXTURE from: " << path << std::endl;
int width, height, channels;
unsigned char* data = stbi_load(path.c_str(), &width, &height, &channels, 0);
if (!data)
{
std::cerr << "[AssetManager] stb_image failed for: " << path << std::endl;
return nullptr;
}
GLenum format = GL_RGBA;
if (channels == 1) format = GL_RED;
else if (channels == 3) format = GL_RGB;
// if channels == 4, already GL_RGBA
GLuint texID = 0;
glGenTextures(1, &texID);
glBindTexture(GL_TEXTURE_2D, texID);
glTexImage2D(GL_TEXTURE_2D, 0, format, width, height, 0,
format, GL_UNSIGNED_BYTE, data);
glGenerateMipmap(GL_TEXTURE_2D);
// Set texture params
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
// Cleanup
glBindTexture(GL_TEXTURE_2D, 0);
stbi_image_free(data);
// Return as void*
return reinterpret_cast<void*>(static_cast<uintptr_t>(texID));
}
case AssetType::SHADER:
{
// --------------------------------------------
// Load a shader using your existing "Shader" class
// --------------------------------------------
// Example usage: path = "shaders/UnlitMaterial" =>
// loads "shaders/UnlitMaterial.vert" and "shaders/UnlitMaterial.frag"
std::cout << "[AssetManager] Loading SHADER from: " << path << std::endl;
// Create a new Shader object on the heap
Shader* newShader = new Shader();
// Build actual paths from the base path
std::string vertPath = path + ".vert";
std::string fragPath = path + ".frag";
// Attempt to load
if (!newShader->Load(vertPath, fragPath))
{
std::cerr << "[AssetManager] Could not load shader: "
<< vertPath << " / " << fragPath << std::endl;
delete newShader; // Cleanup
return nullptr;
}
// Return as void*
return reinterpret_cast<void*>(newShader);
}
case AssetType::SOUND:
{
std::cout << "[AssetManager] Loading SOUND from: " << path << std::endl;
// Stub or real code to load .wav / .ogg
return (void*)0xAAAA8888; // placeholder
}
default:
{
std::cerr << "[AssetManager] Unknown asset type for: " << path << std::endl;
return nullptr;
}
}
}

47
src/Engine/AssetManager.h Normal file
View File

@ -0,0 +1,47 @@
#pragma once
#include <string>
#include <unordered_map>
// Forward-declare your Shader class
class Shader;
// Define types of assets
enum class AssetType
{
TEXTURE,
SHADER,
SOUND,
// Add more as you need
};
// A simple struct to hold the generic pointer
struct GenericAsset
{
void* data = nullptr;
};
// The main AssetManager
class AssetManager
{
public:
AssetManager() = default;
~AssetManager() = default;
// Load an asset from disk (texture, shader, etc.)
// Returns a void* pointer to the loaded resource.
// - For TEXTURE, cast to (GLuint)
// - For SHADER, cast to (Shader*)
// - For SOUND, cast to whatever you store
void* loadAsset(AssetType type, const std::string& path);
private:
// Cache of already loaded assets: key = "type + path"
std::unordered_map<std::string, GenericAsset> m_AssetMap;
// Generate the unique key
std::string generateKey(AssetType type, const std::string& path);
// Actual loading from disk
void* loadAssetFromDisk(AssetType type, const std::string& path);
};

81
src/Rendering/FBO.cpp Normal file
View 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
View 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
View 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
View 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;
};

0
src/TestModel.h Normal file
View File

View File

@ -0,0 +1,279 @@
#include "InspectorWindow.h"
#include <cstdio> // for debugging or printing if needed
#include <cstring> // for strcpy, if needed
#include <glm/gtc/type_ptr.hpp> // Required for glm::value_ptr
#include <vector>
extern std::vector<GameObject> m_GameObjects;
void InspectorWindow::Show()
{
// Increase window/item spacing for a cleaner look
ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(12, 12));
ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(6, 4));
ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(10, 10));
if (ImGui::Begin("Inspector"))
{
// Title label (white text)
ImGui::TextUnformatted("Selected Object Inspector");
ImGui::Separator();
ImGui::Spacing();
// ===========================
// 1) TRANSFORM
// ===========================
// Color the Transform header
ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(1.0f, 1.0f, 0.4f, 1.0f));
bool transformOpen = ImGui::CollapsingHeader("Transform##Main", ImGuiTreeNodeFlags_DefaultOpen);
ImGui::PopStyleColor();
if (transformOpen)
{
Transform* transform = &m_GameObjects[0].transform;
if (ImGui::IsItemHovered())
{
ImGui::BeginTooltip();
ImGui::TextUnformatted("Controls the object's Position, Rotation, and Scale.");
ImGui::EndTooltip();
}
// -----------------------------------
// Position
// -----------------------------------
ImGui::TextUnformatted("Position");
ImGui::Spacing();
{
// We'll assign colors for X, Y, Z buttons
// (normal, hovered, active)
static const ImVec4 colX = ImVec4(1.0f, 0.4f, 0.4f, 1.0f);
static const ImVec4 colXHover = ImVec4(1.0f, 0.6f, 0.6f, 1.0f);
static const ImVec4 colXActive = ImVec4(1.0f, 0.2f, 0.2f, 1.0f);
static const ImVec4 colY = ImVec4(0.4f, 1.0f, 0.4f, 1.0f);
static const ImVec4 colYHover = ImVec4(0.6f, 1.0f, 0.6f, 1.0f);
static const ImVec4 colYActive = ImVec4(0.2f, 1.0f, 0.2f, 1.0f);
static const ImVec4 colZ = ImVec4(0.4f, 0.4f, 1.0f, 1.0f);
static const ImVec4 colZHover = ImVec4(0.6f, 0.6f, 1.0f, 1.0f);
static const ImVec4 colZActive = ImVec4(0.2f, 0.2f, 1.0f, 1.0f);
const char *axisNames[3] = {"X", "Y", "Z"};
// We'll reference transform.position here
float *pos = glm::value_ptr(transform->position);
ImGui::PushID("PositionRow");
for (int i = 0; i < 3; i++)
{
// Determine color set
ImVec4 col, colH, colA;
if (i == 0)
{
col = colX;
colH = colXHover;
colA = colXActive;
}
else if (i == 1)
{
col = colY;
colH = colYHover;
colA = colYActive;
}
else
{
col = colZ;
colH = colZHover;
colA = colZActive;
}
// Push color style for button
ImGui::PushStyleColor(ImGuiCol_Button, col);
ImGui::PushStyleColor(ImGuiCol_ButtonHovered, colH);
ImGui::PushStyleColor(ImGuiCol_ButtonActive, colA);
// Small button with the axis name
if (ImGui::Button(axisNames[i], ImVec2(20, 0)))
{
// No action on click, but we have a box with color
}
ImGui::PopStyleColor(3);
ImGui::SameLine();
ImGui::SetNextItemWidth(60.0f);
ImGui::DragFloat((std::string("##Pos") + axisNames[i]).c_str(), &pos[i], 0.1f);
if (i < 2)
ImGui::SameLine(0, 15);
}
ImGui::PopID();
}
ImGui::Spacing();
ImGui::Separator();
// -----------------------------------
// Rotation
// -----------------------------------
ImGui::TextUnformatted("Rotation");
ImGui::Spacing();
{
// Same approach, but referencing transform.rotation
const char *axisNames[3] = {"X", "Y", "Z"};
float *rot = glm::value_ptr(transform->rotation);
// We can reuse the same color sets
ImGui::PushID("RotationRow");
for (int i = 0; i < 3; i++)
{
// Decide color sets for X, Y, Z
ImVec4 col, colH, colA;
if (i == 0)
{
col = ImVec4(1.0f, 0.4f, 0.4f, 1.0f);
colH = ImVec4(1.0f, 0.6f, 0.6f, 1.0f);
colA = ImVec4(1.0f, 0.2f, 0.2f, 1.0f);
}
else if (i == 1)
{
col = ImVec4(0.4f, 1.0f, 0.4f, 1.0f);
colH = ImVec4(0.6f, 1.0f, 0.6f, 1.0f);
colA = ImVec4(0.2f, 1.0f, 0.2f, 1.0f);
}
else
{
col = ImVec4(0.4f, 0.4f, 1.0f, 1.0f);
colH = ImVec4(0.6f, 0.6f, 1.0f, 1.0f);
colA = ImVec4(0.2f, 0.2f, 1.0f, 1.0f);
}
ImGui::PushStyleColor(ImGuiCol_Button, col);
ImGui::PushStyleColor(ImGuiCol_ButtonHovered, colH);
ImGui::PushStyleColor(ImGuiCol_ButtonActive, colA);
if (ImGui::Button(axisNames[i], ImVec2(20, 0)))
{
// No action
}
ImGui::PopStyleColor(3);
ImGui::SameLine();
ImGui::SetNextItemWidth(60.0f);
ImGui::DragFloat((std::string("##Rot") + axisNames[i]).c_str(), &rot[i], 0.1f);
if (i < 2)
ImGui::SameLine(0, 15);
}
ImGui::PopID();
}
ImGui::Spacing();
ImGui::Separator();
// -----------------------------------
// Scale
// -----------------------------------
ImGui::TextUnformatted("Scale");
ImGui::Spacing();
{
const char *axisNames[3] = {"X", "Y", "Z"};
float *scl = glm::value_ptr(transform->scale);
ImGui::PushID("ScaleRow");
for (int i = 0; i < 3; i++)
{
// same color approach
ImVec4 col, colH, colA;
if (i == 0)
{
col = ImVec4(1.0f, 0.4f, 0.4f, 1.0f);
colH = ImVec4(1.0f, 0.6f, 0.6f, 1.0f);
colA = ImVec4(1.0f, 0.2f, 0.2f, 1.0f);
}
else if (i == 1)
{
col = ImVec4(0.4f, 1.0f, 0.4f, 1.0f);
colH = ImVec4(0.6f, 1.0f, 0.6f, 1.0f);
colA = ImVec4(0.2f, 1.0f, 0.2f, 1.0f);
}
else
{
col = ImVec4(0.4f, 0.4f, 1.0f, 1.0f);
colH = ImVec4(0.6f, 0.6f, 1.0f, 1.0f);
colA = ImVec4(0.2f, 0.2f, 1.0f, 1.0f);
}
ImGui::PushStyleColor(ImGuiCol_Button, col);
ImGui::PushStyleColor(ImGuiCol_ButtonHovered, colH);
ImGui::PushStyleColor(ImGuiCol_ButtonActive, colA);
if (ImGui::Button(axisNames[i], ImVec2(20, 0)))
{
// No action
}
ImGui::PopStyleColor(3);
ImGui::SameLine();
ImGui::SetNextItemWidth(60.0f);
ImGui::DragFloat((std::string("##Scl") + axisNames[i]).c_str(), &scl[i], 0.1f);
if (i < 2)
ImGui::SameLine(0, 15);
}
ImGui::PopID();
}
ImGui::Spacing();
ImGui::Separator();
}
ImGui::Spacing();
// ===========================
// 2) SCRIPT
// ===========================
// We keep script text in white
// if (ImGui::CollapsingHeader("Script##Main", ImGuiTreeNodeFlags_DefaultOpen))
//{
// if (ImGui::IsItemHovered())
// {
// ImGui::BeginTooltip();
// ImGui::TextUnformatted("Attach a script or logic component here.");
// ImGui::EndTooltip();
// }
// ImGui::TextUnformatted("Script Name:");
// ImGui::SameLine();
// {
// char buffer[128];
// std::snprintf(buffer, sizeof(buffer), "%s", script.scriptName.c_str());
// ImGui::SetNextItemWidth(-1);
// if (ImGui::InputText("##ScriptName", buffer, sizeof(buffer)))
// {
// script.scriptName = buffer;
// }
// }
// ImGui::Spacing();
// ImGui::TextUnformatted("Script Enabled:");
// ImGui::SameLine();
// ImGui::Checkbox("##ScriptEnabled", &script.enabled);
// ImGui::Spacing();
// ImGui::Separator();
//}
ImGui::End();
} //
// Restore style
ImGui::PopStyleVar(3);
}

View File

@ -0,0 +1,35 @@
#pragma once
#include <string>
#include <glm/glm.hpp> // or <glm/vec3.hpp> if you prefer
#include "imgui.h"
#include "Componenets/GameObject.h"
#include "Componenets/Mesh.h"
#include "Componenets/Transform.h"
// Example struct for a Script component
struct Script
{
std::string scriptName = "MyBehavior.lua";
bool enabled = true;
};
// The Inspector window class
class InspectorWindow
{
public:
// Constructor / Destructor
InspectorWindow() = default;
~InspectorWindow() = default;
// Show the window (call each frame)
// Pass references to your components, so any changes get applied to them.
void Show();
private:
// You can store additional state or styling here if needed
// e.g. bool m_SomeInternalFlag = false;
};

View 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();
}

View 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;
};

View File

@ -0,0 +1,152 @@
#include "PerformanceWindow.h"
#include "imgui.h"
#include <algorithm> // for std::max_element, etc.
extern int LoaddedAssets;
// Initialize static members
int PerformanceWindow::m_OpenGLCallCount = 0;
int PerformanceWindow::m_TriangleCount = 0;
// We'll store up to 60 data points for each stat.
static float s_FpsHistory[60] = {0.0f};
static float s_MsHistory[60] = {0.0f};
static float s_CallsHistory[60] = {0.0f};
static float s_TriangleHistory[60] = {0.0f};
// Current dynamic max scale for FPS and ms
static float s_FpsScale = 120.0f; // default starting scale for FPS
static float s_MsScale = 25.0f; // default starting scale for ms
// This function shifts the old values left and appends a new value at the end.
static void PushValueToHistory(float* historyArray, int historySize, float newValue)
{
for (int i = 0; i < historySize - 1; i++)
historyArray[i] = historyArray[i + 1];
historyArray[historySize - 1] = newValue;
}
// We'll track when we last pushed data to our history.
static double s_LastPushTime = 0.0;
// We'll also track when we last updated the scale
static double s_LastScaleUpdate = 0.0;
// Update counters from the outside
void PerformanceWindow::UpdatePerformanceStats(int newCallCount, int newTriangleCount)
{
m_OpenGLCallCount = newCallCount;
m_TriangleCount = newTriangleCount;
}
void PerformanceWindow::Show(float fps, float ms)
{
// 1) Get current time from ImGui's internal clock
double currentTime = ImGui::GetTime();
// 2) If at least 0.05s has passed, push new data (about 20 updates per second)
if ((currentTime - s_LastPushTime) >= 0.05)
{
s_LastPushTime = currentTime;
// Push new values into our history arrays
PushValueToHistory(s_FpsHistory, 60, fps);
PushValueToHistory(s_MsHistory, 60, ms);
PushValueToHistory(s_CallsHistory, 60, (float)m_OpenGLCallCount);
PushValueToHistory(s_TriangleHistory, 60, (float)m_TriangleCount);
}
// 3) Every 1 second, recalculate the max scale for FPS and ms
if ((currentTime - s_LastScaleUpdate) >= 1.0)
{
s_LastScaleUpdate = currentTime;
// Find the maximum in s_FpsHistory
float maxFps = 0.0f;
for (int i = 0; i < 60; i++)
{
if (s_FpsHistory[i] > maxFps)
maxFps = s_FpsHistory[i];
}
// Scale it by +15%, ensure it's not below 1.0
maxFps *= 1.15f;
if (maxFps < 1.0f) maxFps = 1.0f;
s_FpsScale = maxFps;
// Find the maximum in s_MsHistory
float maxMs = 0.0f;
for (int i = 0; i < 60; i++)
{
if (s_MsHistory[i] > maxMs)
maxMs = s_MsHistory[i];
}
// Scale it by +15%, ensure it's not below 1.0
maxMs *= 1.15f;
if (maxMs < 1.0f) maxMs = 1.0f;
s_MsScale = maxMs;
}
// Optional style adjustments
ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(10, 10));
ImGui::Begin("Performance");
// Colored header
ImGui::TextColored(ImVec4(1.0f, 0.8f, 0.2f, 1.0f), "Performance Stats");
ImGui::Separator();
// Show current FPS/ms
ImGui::TextColored(ImVec4(0.4f, 1.0f, 0.4f, 1.0f), "FPS: %.1f", fps);
ImGui::SameLine();
ImGui::TextColored(ImVec4(0.4f, 1.0f, 0.8f, 1.0f), "| ms: %.3f", ms);
// Graphs for FPS + MS
// min = 0, max = s_FpsScale or s_MsScale
ImGui::PlotLines("FPS",
s_FpsHistory,
IM_ARRAYSIZE(s_FpsHistory),
0,
nullptr,
0.0f,
s_FpsScale,
ImVec2(0, 60));
ImGui::PlotHistogram("ms/frame",
s_MsHistory,
IM_ARRAYSIZE(s_MsHistory),
0,
nullptr,
0.0f,
s_MsScale,
ImVec2(0, 60));
ImGui::Separator();
// Show OpenGL calls + Triangles
ImGui::Text("OpenGL Calls: %d", m_OpenGLCallCount);
ImGui::PlotLines("GL Calls",
s_CallsHistory,
IM_ARRAYSIZE(s_CallsHistory),
0,
nullptr,
0.0f,
300.0f,
ImVec2(0, 50));
ImGui::Text("Triangles: %d", m_TriangleCount);
ImGui::PlotHistogram("Triangles",
s_TriangleHistory,
IM_ARRAYSIZE(s_TriangleHistory),
0,
nullptr,
0.0f,
5000.0f,
ImVec2(0, 50));
ImGui::Separator();
// Show asset count
ImGui::TextColored(ImVec4(0.4f, 1.0f, 0.4f, 1.0f), "Assets: %d", LoaddedAssets);
ImGui::End();
ImGui::PopStyleVar();
}

View File

@ -0,0 +1,22 @@
// src/Windows/PerformanceWindow.h
#pragma once
class PerformanceWindow
{
public:
// Displays the performance window in ImGui.
// fps = frames per second
// ms = milliseconds per frame
void Show(float fps, float ms);
// Updates the counters for OpenGL calls and triangle count.
void UpdatePerformanceStats(int newCallCount, int newTriangleCount);
private:
float max_ms;
// These are static so they're shared across all instances
static int m_OpenGLCallCount;
static int m_TriangleCount;
};

View File

@ -0,0 +1,261 @@
// RenderWindow.cpp
#include "RenderWindow.h"
#include <vector> // Add this line
#include <GL/glew.h>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtc/type_ptr.hpp>
#include "imgui.h"
#include "Componenets/GameObject.h"
#include "Componenets/Mesh.h"
#include "Componenets/Transform.h"
extern std::vector<GameObject> m_GameObjects;
#define CAM_FOV 45.0f
#define CAM_NEAR_PLAIN 0.1f
#define CAM_FAR_PLAIN 1000.0f
// Include your AssetManager & Shader headers
#include "Engine/AssetManager.h"
#include "Rendering/Shader.h"
// Extern reference to our global (or extern) asset manager
extern AssetManager g_AssetManager;
// Example cube data (position + UVs)
static float g_CubeVertices[] =
{
// FRONT (z=+1)
-1.f, -1.f, 1.f, 0.f, 0.f,
1.f, -1.f, 1.f, 1.f, 0.f,
1.f, 1.f, 1.f, 1.f, 1.f,
-1.f, 1.f, 1.f, 0.f, 1.f,
// BACK (z=-1)
-1.f, -1.f, -1.f, 1.f, 0.f,
1.f, -1.f, -1.f, 0.f, 0.f,
1.f, 1.f, -1.f, 0.f, 1.f,
-1.f, 1.f, -1.f, 1.f, 1.f,
// LEFT (x=-1)
-1.f, -1.f, -1.f, 0.f, 0.f,
-1.f, -1.f, 1.f, 1.f, 0.f,
-1.f, 1.f, 1.f, 1.f, 1.f,
-1.f, 1.f, -1.f, 0.f, 1.f,
// RIGHT (x=+1)
1.f, -1.f, -1.f, 1.f, 0.f,
1.f, -1.f, 1.f, 0.f, 0.f,
1.f, 1.f, 1.f, 0.f, 1.f,
1.f, 1.f, -1.f, 1.f, 1.f,
// TOP (y=+1)
-1.f, 1.f, -1.f, 0.f, 0.f,
1.f, 1.f, -1.f, 1.f, 0.f,
1.f, 1.f, 1.f, 1.f, 1.f,
-1.f, 1.f, 1.f, 0.f, 1.f,
// BOTTOM (y=-1)
-1.f, -1.f, -1.f, 1.f, 0.f,
1.f, -1.f, -1.f, 0.f, 0.f,
1.f, -1.f, 1.f, 0.f, 1.f,
-1.f, -1.f, 1.f, 1.f, 1.f,
};
static unsigned int g_CubeIndices[] =
{
// Front
0,1,2, 2,3,0,
// Back
4,5,6, 6,7,4,
// Left
8,9,10, 10,11,8,
// Right
12,13,14, 14,15,12,
// Top
16,17,18, 18,19,16,
// Bottom
20,21,22, 22,23,20
};
void RenderWindow::Show()
{
ImGui::Begin("OpenGL Output");
ImVec2 size = ImGui::GetContentRegionAvail();
int w = static_cast<int>(size.x);
int h = static_cast<int>(size.y);
if (!m_Initialized)
{
InitGLResources();
m_Initialized = true;
}
// If there's space, render to the FBO, then show it as an ImGui image
if (w > 0 && h > 0)
{
if (w != m_LastWidth || h != m_LastHeight)
{
m_FBO.Create(w, h);
m_LastWidth = w;
m_LastHeight = h;
}
RenderSceneToFBO();
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 SHADER from the asset manager
// ----------------------------------------------------
{
void* shaderAsset = g_AssetManager.loadAsset(AssetType::SHADER, "assets/shaders/UnlitMaterial");
if (!shaderAsset)
{
fprintf(stderr, "[RenderWindow] Failed to load shader via AssetManager.\n");
return;
}
// Cast back to your Shader class
m_ShaderPtr = static_cast<Shader*>(shaderAsset);
}
// ----------------------------------------------------
// 2) Create VAO/VBO/EBO for the cube
// ----------------------------------------------------
glGenVertexArrays(1, &m_VAO);
glBindVertexArray(m_VAO);
glGenBuffers(1, &m_VBO);
glBindBuffer(GL_ARRAY_BUFFER, m_VBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(g_CubeVertices), g_CubeVertices, GL_STATIC_DRAW);
glGenBuffers(1, &m_EBO);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_EBO);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(g_CubeIndices), g_CubeIndices, GL_STATIC_DRAW);
// Position = location 0, UV = location 1
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE,
5 * sizeof(float), (void*)0);
glEnableVertexAttribArray(0);
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE,
5 * sizeof(float), (void*)(3 * sizeof(float)));
glEnableVertexAttribArray(1);
glBindVertexArray(0);
// ----------------------------------------------------
// 3) Load TEXTURE from the asset manager
// ----------------------------------------------------
{
void* texAsset = g_AssetManager.loadAsset(AssetType::TEXTURE, "assets/textures/wood.png");
if (!texAsset)
{
fprintf(stderr, "[RenderWindow] Failed to load texture.\n");
}
else
{
// Cast from void* to GLuint
m_TextureID = static_cast<GLuint>(reinterpret_cast<uintptr_t>(texAsset));
}
}
// ----------------------------------------------------
// 4) Initialize GameObjects
// ----------------------------------------------------
}
void RenderWindow::RenderSceneToFBO()
{
m_RotationAngle += 0.1f; // spin per frame
// Bind the FBO
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 loaded shader
if (!m_ShaderPtr)
return; // Can't render without a shader
m_ShaderPtr->Use();
GLuint programID = m_ShaderPtr->GetProgramID();
// Define view and projection matrices once
glm::mat4 view = glm::translate(glm::mat4(1.f), glm::vec3(0.f, 0.f, -5.f));
float aspect = (m_LastHeight != 0) ? (float)m_LastWidth / (float)m_LastHeight : 1.0f;
glm::mat4 proj = glm::perspective(glm::radians(CAM_FOV), aspect, CAM_NEAR_PLAIN, CAM_FAR_PLAIN);
// Iterate over each GameObject and render it
for (auto& obj : m_GameObjects)
{
// -----------------------------------
// 1) Build MVP from obj.transform
// -----------------------------------
glm::mat4 model = glm::mat4(1.f);
// Translate
model = glm::translate(model, obj.transform.position);
// Rotate around X, Y, Z
model = glm::rotate(model, glm::radians(obj.transform.rotation.x), glm::vec3(1.f, 0.f, 0.f));
model = glm::rotate(model, glm::radians(obj.transform.rotation.y), glm::vec3(0.f, 1.f, 0.f));
model = glm::rotate(model, glm::radians(obj.transform.rotation.z), glm::vec3(0.f, 0.f, 1.f));
// Scale
model = glm::scale(model, obj.transform.scale);
// Compute MVP
glm::mat4 mvp = proj * view * model;
// Pass MVP to the shader
GLint mvpLoc = glGetUniformLocation(programID, "uMVP");
glUniformMatrix4fv(mvpLoc, 1, GL_FALSE, glm::value_ptr(mvp));
// -----------------------------------
// 2) Bind the object's texture
// -----------------------------------
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, obj.mesh.textureID);
// Set the sampler uniform to texture unit 0
GLint texLoc = glGetUniformLocation(programID, "uTexture");
glUniform1i(texLoc, 0);
// -----------------------------------
// 3) Draw the object's mesh
// -----------------------------------
glBindVertexArray(obj.mesh.vao);
glDrawElements(GL_TRIANGLES, obj.mesh.indexCount, GL_UNSIGNED_INT, nullptr);
// Unbind for cleanliness
glBindVertexArray(0);
glBindTexture(GL_TEXTURE_2D, 0);
}
// Cleanup
glUseProgram(0);
m_FBO.Unbind();
}

View File

@ -0,0 +1,38 @@
#pragma once
#include "../Rendering/FBO.h"
#include <glm/glm.hpp>
#include "Rendering/Shader.h" //
class RenderWindow
{
public:
void Show();
private:
void InitGLResources();
void RenderSceneToFBO();
// Offscreen render target
FBO m_FBO;
// Keep track if we've initialized
bool m_Initialized = false;
// GL objects for the cube
unsigned int m_VAO = 0;
unsigned int m_VBO = 0;
unsigned int m_EBO = 0;
// Spin
float m_RotationAngle = 0.f;
int m_LastWidth = 0;
int m_LastHeight = 0;
// The loaded texture
unsigned int m_TextureID = 0;
// The loaded shader program (via AssetManager)
Shader* m_ShaderPtr = nullptr;
};

View File

@ -1,344 +1,29 @@
// src/main.cpp
#include <GLFW/glfw3.h>
#include "imgui.h"
#include "imgui_impl_glfw.h"
#include "imgui_impl_opengl3.h"
#include "../IconsFontAwesome6.h" // Include the Font Awesome icons header
#include <cstdio>
#include "Engine.h"
#include <iostream>
#include <stdio.h>
#include <vector>
#include <string>
#define DEBUG 1
#ifdef DEBUG
#define LOGPOINT(msg) std::cout << "[TESRCT] [" << __func__ << ":" << __LINE__ << "] " << (msg) << std::endl;
#else
#define LOGPOINT(msg)
#endif
// Logger Implementation
enum class LogLevel { INFO, WARNING, ERROR };
struct LogEntry {
LogLevel level;
std::string message;
};
class Logger {
public:
static Logger& GetInstance() {
static Logger instance;
return instance;
}
void Log(LogLevel level, const std::string& message) {
entries.emplace_back(LogEntry{ level, message });
if (entries.size() > max_entries)
entries.erase(entries.begin());
}
const std::vector<LogEntry>& GetEntries() const { return entries; }
void Clear() { // Added Clear method
entries.clear();
}
private:
Logger() : max_entries(1000) {}
std::vector<LogEntry> entries;
size_t max_entries;
};
// Function Declarations
void ShowMainMenuBar();
void ShowViewport();
void ShowConsole(bool* p_open);
// 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);
}
DEBUG_PRINT("[START] Creating Global Engine ");
// Helper function to get color based on log level
ImVec4 GetColorForLogLevel(LogLevel level)
{
switch (level)
MyEngine engine;
DEBUG_PRINT("[OK] Creating Global Engine ");
// Initialize the engine (creates GLFW window, sets up ImGui, etc.)
if (!engine.Init(1280, 720, "Tesseract Engine"))
{
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);
}
}
int main(int, char**)
{
LOGPOINT("Loading Engine");
Logger::GetInstance().Log(LogLevel::INFO, "Loading engine...");
// Setup GLFW error callback
glfwSetErrorCallback(glfw_error_callback);
// Initialize GLFW
if (!glfwInit())
return 1;
// GL 3.0 + GLSL 130
const char* glsl_version = "#version 330";
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 0);
// Create window with graphics context
GLFWwindow* window = glfwCreateWindow(1280, 720, "Tesseract Engine", NULL, NULL);
if (window == NULL)
return 1;
glfwMakeContextCurrent(window);
glfwSwapInterval(1); // Enable vsync
// 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 config;
config.MergeMode = true;
config.PixelSnapH = true;
// Path 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)
{
fprintf(stderr, "Failed to load default font!\n");
fprintf(stderr, "Failed to initialize engine.\n");
return 1;
}
// Define the Font Awesome icon range
static const ImWchar icons_ranges[] = { ICON_MIN_FA, ICON_MAX_FA, 0 };
// Merge Font Awesome icons
config.GlyphMinAdvanceX = 13.0f; // Adjust if necessary
ImFont* fa_font = io.Fonts->AddFontFromFileTTF(fa_font_path, 16.0f, &config, icons_ranges);
if (!fa_font)
{
fprintf(stderr, "Failed to load Font Awesome font!\n");
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);
// Example log messages
//Logger::GetInstance().Log(LogLevel::INFO, "Engine initialized successfully.");
//Logger::GetInstance().Log(LogLevel::WARNING, "This is a warning message.");
//Logger::GetInstance().Log(LogLevel::ERROR, "This is an error message.");
Logger::GetInstance().Log(LogLevel::INFO, "Done!");
// Variables for Console
bool show_console = true;
// Main loop
while (!glfwWindowShouldClose(window))
{
// Poll and handle events (inputs, window resize, etc.)
glfwPollEvents();
// Start the Dear ImGui frame
ImGui_ImplOpenGL3_NewFrame();
ImGui_ImplGlfw_NewFrame();
ImGui::NewFrame();
// Create DockSpace
ImGuiWindowFlags dockspace_flags = ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoCollapse |
ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoMove |
ImGuiWindowFlags_NoBringToFrontOnFocus | ImGuiWindowFlags_NoNavFocus;
const ImGuiViewport* viewport = ImGui::GetMainViewport();
ImGui::SetNextWindowPos(viewport->Pos);
ImGui::SetNextWindowSize(viewport->Size);
ImGui::SetNextWindowViewport(viewport->ID);
ImGui::PushStyleVar(ImGuiStyleVar_WindowRounding, 0.0f);
ImGui::PushStyleVar(ImGuiStyleVar_WindowBorderSize, 0.0f);
ImGui::Begin("DockSpace", 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();
ShowViewport();
ShowConsole(&show_console);
// Rendering
ImGui::Render();
int display_w, display_h;
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);
}
engine.Run();
// Cleanup
ImGui_ImplOpenGL3_Shutdown();
ImGui_ImplGlfw_Shutdown();
ImGui::DestroyContext();
glfwDestroyWindow(window);
glfwTerminate();
engine.Cleanup();
return 0;
}
// Function Definitions
// 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"))
{
if (ImGui::MenuItem("Show Console", NULL, true)) { /* Toggle Console */ }
if (ImGui::MenuItem("Toggle Viewport")) { /* Toggle Viewport */ }
ImGui::EndMenu();
}
ImGui::EndMainMenuBar();
}
}
// 2. Viewport Panel
void ShowViewport()
{
ImGui::Begin("Viewport", NULL, ImGuiWindowFlags_NoCollapse);
// Get the size of the viewport
ImVec2 viewport_size = ImGui::GetContentRegionAvail();
// For demonstration, we'll render a colored rectangle
// In a real engine, you'd render your scene here
// Calculate the center position
ImVec2 pos = ImGui::GetCursorScreenPos();
// Define rectangle dimensions
ImVec2 rect_min = pos;
ImVec2 rect_max = ImVec2(pos.x + viewport_size.x, pos.y + viewport_size.y);
// Render a colored rectangle
ImGui::GetWindowDrawList()->AddRectFilled(rect_min, rect_max, IM_COL32(100, 100, 200, 255));
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();
}

455
vendor/gcml/gcml.h vendored Normal file
View 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, "%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

View File

@ -1,6 +0,0 @@
cmake_minimum_required(VERSION 3.22)
project(glad)
add_library(glad)
target_sources(glad PRIVATE src/glad.c)
target_include_directories(glad PUBLIC include)

View File

@ -1,11 +0,0 @@
cmake_minimum_required(VERSION 3.22)
project(stb)
file(GLOB_RECURSE SOURCES src/*.cpp)
add_library(stb)
target_include_directories(stb PUBLIC include)
target_sources(stb PRIVATE ${SOURCES})

View File

@ -1,5 +1,4 @@
#ifndef STB_IMAG_H
#define STB_IMAG_H
#pragma once
/* stb_image - v2.30 - public domain image loader - http://nothings.org/stb
no warranty implied; use at your own risk
@ -7990,4 +7989,3 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
------------------------------------------------------------------------------
*/
#endif

View File

@ -1,2 +0,0 @@
#define STB_IMAGE_IMPLEMENTATION
#include <stb_image.h>