Added Sub meshing Asseet Loader : Broak Play Pause Button

When you resume the Asset cache returns an invalid Mesh
The Asset Cache needs to be updated
This commit is contained in:
OusmBlueNinja 2024-12-31 02:40:23 -06:00
parent 41a09cc8f3
commit a558ea092b
16 changed files with 941 additions and 778 deletions

View File

@ -3,14 +3,17 @@ local Math = require("./assets/scripts/math") -- Require the enhanced math modul
local Engine = require("./assets/scripts/engine")
local GameObjectName = "Bacround"
-- Variables to track elapsed time and rotation
local elapsedTime = 0
local rotationSpeed = 45 -- Degrees per second for spinning
local rotationSpeed = 25 -- Degrees per second for spinning
local new_rotation = 0
-- Variables for bobbing effect
local initial_position = {x = 0, y = 0, z = 0} -- To store the gun's initial position
local bobAmplitude = 0.5 -- Amplitude of the bobbing (units)
local bobAmplitude = 5 -- Amplitude of the bobbing (units)
local bobFrequency = 0.5 -- Frequency of the bobbing (oscillations per second)
-- Reference to the Gun GameObject and its Transform component
@ -26,7 +29,7 @@ function OnInit()
if not gun then
gun = Engine.GetGameObjectByTag("Gun")
gun = Engine.GetGameObjectByTag(GameObjectName)
if gun then
transform = gun:GetComponent("Transform")
if transform then
@ -68,7 +71,7 @@ end
function OnUpdate(deltaTime)
-- Ensure that the Gun and its Transform component are valid
if not gun then
gun = Engine.GetGameObjectByTag("Gun")
gun = Engine.GetGameObjectByTag(GameObjectName)
if gun then
transform = gun:GetComponent("Transform")
if transform then

View File

@ -1,29 +1,49 @@
#version 330 core
// Struct to hold an array of diffuse textures
struct TextureArray {
sampler2D texture_diffuse[32]; // Array of diffuse texture samplers
sampler2D texture_diffuse[32]; // Array of diffuse textures
// You can add more texture types here (e.g., specular, normal) if needed
};
// Uniforms
uniform TextureArray uTextures; // Array of diffuse textures
uniform TextureArray uTextures; // Array of textures
uniform int uNumDiffuseTextures; // Number of active diffuse textures
// Input variables from the vertex shader
in vec2 TexCoords; // Texture coordinates
flat in int TextureIndex; // Texture index for this fragment
in vec2 TexCoord; // From vertex shader
in vec3 Normal; // From vertex shader
in vec3 FragPos; // From vertex shader
// Output fragment color
out vec4 FragColor;
out vec4 FragColor; // Final fragment color
// Example lighting parameters
uniform vec3 lightPos; // Position of the light source
uniform vec3 viewPos; // Position of the camera/viewer
void main()
{
// Clamp the texture index to prevent out-of-bounds access
int texIndex = clamp(TextureIndex, 0, uNumDiffuseTextures - 1);
// Sample the texture using the provided index and texture coordinates
vec4 sampledColor = texture(uTextures.texture_diffuse[texIndex], TexCoords);
// Set the final fragment color
FragColor = sampledColor;
// Normalize the normal vector
vec3 norm = normalize(Normal);
// Calculate the direction from the fragment to the light
vec3 lightDir = normalize(lightPos - FragPos);
// Compute the diffuse intensity
float diff = max(dot(norm, lightDir), 0.0);
// Initialize diffuse color
vec4 diffuseColor = vec4(0.0);
// Sample and accumulate diffuse textures
for(int i = 0; i < uNumDiffuseTextures; ++i)
{
diffuseColor += texture(uTextures.texture_diffuse[i], TexCoord);
}
// Apply the diffuse intensity
diffuseColor *= diff;
// Simple ambient lighting
vec3 ambient = 0.1 * diffuseColor.rgb;
// Final color combining ambient and diffuse components
FragColor = vec4(ambient + diffuseColor.rgb, diffuseColor.a);
}

View File

@ -1,33 +1,27 @@
#version 330 core
// Input vertex attributes (from the VAO)
layout(location = 0) in vec3 aPos; // Vertex position
layout(location = 1) in vec3 aNormal; // Vertex normal
layout(location = 2) in vec2 aTexCoords; // Vertex texture coordinates
layout(location = 3) in int aTexIndex; // Texture index (integer)
layout(location = 0) in vec3 aPos; // Vertex position
layout(location = 1) in vec2 aTexCoord; // Texture coordinate
layout(location = 2) in vec3 aNormal; // Vertex normal
// Uniforms
uniform mat4 uMVP; // Model-View-Projection matrix
uniform mat4 uModel; // Model matrix
// Output variables to the fragment shader
out vec2 TexCoords; // Passed texture coordinates
flat out int TextureIndex; // Passed texture index
out vec2 TexCoord; // Passed to fragment shader
out vec3 Normal; // Passed to fragment shader
out vec3 FragPos; // Passed to fragment shader
void main()
{
// Transform vertex position to clip space
// Compute the fragment position in world space
FragPos = vec3(uModel * vec4(aPos, 1.0));
// Transform the normal vector
Normal = mat3(transpose(inverse(uModel))) * aNormal;
// Pass through the texture coordinate
TexCoord = aTexCoord;
// Final vertex position
gl_Position = uMVP * vec4(aPos, 1.0);
// Transform vertex position to world space
vec3 FragPos = vec3(uModel * vec4(aPos, 1.0));
// Transform normal to world space
vec3 Normal = mat3(transpose(inverse(uModel))) * aNormal;
// Pass through texture coordinates
TexCoords = aTexCoords;
// Pass through the texture index
TextureIndex = aTexIndex;
}

View File

@ -4,7 +4,8 @@ Size=1920,1177
Collapsed=0
[Window][Debug##Default]
Pos=468,549
ViewportPos=926,1030
ViewportId=0x16723995
Size=400,400
Collapsed=0
@ -73,28 +74,28 @@ Collapsed=0
DockId=0x00000016,0
[Window][Editor##EditorWindow]
Pos=274,27
Size=1260,751
Pos=410,27
Size=1124,709
Collapsed=0
DockId=0x00000017,0
[Window][Performance##performance]
Pos=8,594
Size=264,575
Pos=8,761
Size=400,408
Collapsed=0
DockId=0x0000001C,0
[Window][Logger##logger]
Pos=8,395
Size=400,364
Collapsed=0
DockId=0x0000001A,0
[Window][Logger##logger]
Pos=274,780
Size=612,389
Collapsed=0
DockId=0x0000001B,0
[Window][Lua Text Editor##LuaEditor]
Pos=888,780
Size=646,389
Pos=410,738
Size=1124,431
Collapsed=0
DockId=0x0000001C,0
DockId=0x00000018,0
[Window][Scene Window@SceneWindow]
Pos=8,27
@ -104,7 +105,7 @@ DockId=0x0000000F,0
[Window][Scene Window##SceneWindow]
Pos=8,27
Size=264,565
Size=400,366
Collapsed=0
DockId=0x00000019,0
@ -115,10 +116,10 @@ Collapsed=0
DockId=0x00000011,0
[Window][Profiler]
Pos=888,780
Size=646,389
Pos=410,738
Size=1124,431
Collapsed=0
DockId=0x0000001C,1
DockId=0x00000018,1
[Table][0xE9E836E4,4]
Column 0 Weight=1.2999
@ -127,34 +128,34 @@ Column 2 Weight=0.6474
Column 3 Weight=1.0088
[Docking][Data]
DockSpace ID=0x14621557 Window=0x3DA2F1DE Pos=8,27 Size=1904,1142 Split=X Selected=0xF7365A5A
DockNode ID=0x00000013 Parent=0x14621557 SizeRef=264,1142 Split=Y Selected=0x818D04BB
DockNode ID=0x00000019 Parent=0x00000013 SizeRef=264,565 HiddenTabBar=1 Selected=0x1D5D92B6
DockNode ID=0x0000001A Parent=0x00000013 SizeRef=264,575 Selected=0x818D04BB
DockNode ID=0x00000014 Parent=0x14621557 SizeRef=1638,1142 Split=X
DockNode ID=0x00000015 Parent=0x00000014 SizeRef=1526,1142 Split=X
DockNode ID=0x00000011 Parent=0x00000015 SizeRef=265,1142 Selected=0x1D5D92B6
DockNode ID=0x00000012 Parent=0x00000015 SizeRef=1259,1142 Split=X
DockNode ID=0x00000009 Parent=0x00000012 SizeRef=364,1142 Split=Y Selected=0x3DC5AC3F
DockNode ID=0x00000005 Parent=0x00000009 SizeRef=364,745 Split=Y Selected=0x3DC5AC3F
DockNode ID=0x0000000B Parent=0x00000005 SizeRef=364,452 HiddenTabBar=1 Selected=0x3DC5AC3F
DockNode ID=0x0000000C Parent=0x00000005 SizeRef=364,291 Selected=0xAE3C694A
DockNode ID=0x00000006 Parent=0x00000009 SizeRef=364,395 HiddenTabBar=1 Selected=0x726D8899
DockNode ID=0x0000000A Parent=0x00000012 SizeRef=1538,1142 Split=X
DockNode ID=0x00000007 Parent=0x0000000A SizeRef=357,1142 Selected=0x7737E8B2
DockNode ID=0x00000008 Parent=0x0000000A SizeRef=1545,1142 Split=X
DockNode ID=0x00000001 Parent=0x00000008 SizeRef=1202,1142 Split=Y Selected=0xDF0EC458
DockNode ID=0x00000003 Parent=0x00000001 SizeRef=1202,849 Split=Y Selected=0xDF0EC458
DockNode ID=0x0000000D Parent=0x00000003 SizeRef=1202,571 Split=Y Selected=0xDFF75B3F
DockNode ID=0x00000017 Parent=0x0000000D SizeRef=1303,751 CentralNode=1 HiddenTabBar=1 Selected=0xDFF75B3F
DockNode ID=0x00000018 Parent=0x0000000D SizeRef=1303,389 Split=X Selected=0x9B5D3198
DockNode ID=0x0000001B Parent=0x00000018 SizeRef=612,680 HiddenTabBar=1 Selected=0x1C0788A1
DockNode ID=0x0000001C Parent=0x00000018 SizeRef=645,680 Selected=0x7D9E6BA2
DockNode ID=0x0000000E Parent=0x00000003 SizeRef=1202,569 Selected=0xE98146C5
DockNode ID=0x00000004 Parent=0x00000001 SizeRef=1202,291 Selected=0x9DD4E196
DockNode ID=0x00000002 Parent=0x00000008 SizeRef=334,1142 HiddenTabBar=1 Selected=0x36DC96AB
DockNode ID=0x00000016 Parent=0x00000014 SizeRef=376,1142 HiddenTabBar=1 Selected=0x8D0E8380
DockSpace ID=0xC6145A92 Pos=8,27 Size=1904,1142 Split=X
DockNode ID=0x0000000F Parent=0xC6145A92 SizeRef=301,1142 Selected=0xA8433A03
DockNode ID=0x00000010 Parent=0xC6145A92 SizeRef=1601,1142 CentralNode=1
DockSpace ID=0x14621557 Window=0x3DA2F1DE Pos=8,50 Size=1904,1142 Split=X Selected=0xF7365A5A
DockNode ID=0x00000013 Parent=0x14621557 SizeRef=400,1142 Split=Y Selected=0x818D04BB
DockNode ID=0x0000001B Parent=0x00000013 SizeRef=264,456 Split=Y Selected=0x1D5D92B6
DockNode ID=0x00000019 Parent=0x0000001B SizeRef=264,366 HiddenTabBar=1 Selected=0x1D5D92B6
DockNode ID=0x0000001A Parent=0x0000001B SizeRef=264,364 HiddenTabBar=1 Selected=0x1C0788A1
DockNode ID=0x0000001C Parent=0x00000013 SizeRef=264,254 HiddenTabBar=1 Selected=0x818D04BB
DockNode ID=0x00000014 Parent=0x14621557 SizeRef=862,1142 Split=X
DockNode ID=0x00000015 Parent=0x00000014 SizeRef=484,1142 Split=X
DockNode ID=0x00000011 Parent=0x00000015 SizeRef=265,1142 Selected=0x1D5D92B6
DockNode ID=0x00000012 Parent=0x00000015 SizeRef=1259,1142 Split=X
DockNode ID=0x00000009 Parent=0x00000012 SizeRef=364,1142 Split=Y Selected=0x3DC5AC3F
DockNode ID=0x00000005 Parent=0x00000009 SizeRef=364,745 Split=Y Selected=0x3DC5AC3F
DockNode ID=0x0000000B Parent=0x00000005 SizeRef=364,452 HiddenTabBar=1 Selected=0x3DC5AC3F
DockNode ID=0x0000000C Parent=0x00000005 SizeRef=364,291 Selected=0xAE3C694A
DockNode ID=0x00000006 Parent=0x00000009 SizeRef=364,395 HiddenTabBar=1 Selected=0x726D8899
DockNode ID=0x0000000A Parent=0x00000012 SizeRef=1538,1142 Split=X
DockNode ID=0x00000007 Parent=0x0000000A SizeRef=357,1142 Selected=0x7737E8B2
DockNode ID=0x00000008 Parent=0x0000000A SizeRef=1545,1142 Split=X
DockNode ID=0x00000001 Parent=0x00000008 SizeRef=1202,1142 Split=Y Selected=0xDF0EC458
DockNode ID=0x00000003 Parent=0x00000001 SizeRef=1202,849 Split=Y Selected=0xDF0EC458
DockNode ID=0x0000000D Parent=0x00000003 SizeRef=1202,571 Split=Y Selected=0xDFF75B3F
DockNode ID=0x00000017 Parent=0x0000000D SizeRef=1303,252 CentralNode=1 HiddenTabBar=1 Selected=0xDFF75B3F
DockNode ID=0x00000018 Parent=0x0000000D SizeRef=1303,431 Selected=0x7D9E6BA2
DockNode ID=0x0000000E Parent=0x00000003 SizeRef=1202,569 Selected=0xE98146C5
DockNode ID=0x00000004 Parent=0x00000001 SizeRef=1202,291 Selected=0x9DD4E196
DockNode ID=0x00000002 Parent=0x00000008 SizeRef=334,1142 HiddenTabBar=1 Selected=0x36DC96AB
DockNode ID=0x00000016 Parent=0x00000014 SizeRef=376,1142 HiddenTabBar=1 Selected=0x8D0E8380
DockSpace ID=0xC6145A92 Pos=8,27 Size=1904,1142 Split=X
DockNode ID=0x0000000F Parent=0xC6145A92 SizeRef=301,1142 Selected=0xA8433A03
DockNode ID=0x00000010 Parent=0xC6145A92 SizeRef=1601,1142 CentralNode=1

View File

@ -3,99 +3,161 @@ Entities:
Name: Bacround
Components:
Transform:
Position: [-0.200000003, 244.5, -220.699997]
Rotation: [0, -88, 0]
Position: [0, 400, 0]
Rotation: [0, -90, 0]
Scale: [1, 1, 1]
Mesh:
vao: 4
indexCount: 786801
textures:
- id: 34
type: texture_diffuse
path: textures/lion.tga
- id: 12
type: texture_diffuse
path: textures/background.tga
- id: 13
type: texture_diffuse
path: textures/vase_plant.tga
- id: 14
type: texture_diffuse
path: textures/sponza_arch_diff.tga
- id: 15
type: texture_diffuse
path: textures/spnza_bricks_a_diff.tga
- id: 16
type: texture_diffuse
path: textures/sponza_ceiling_a_diff.tga
- id: 17
type: texture_diffuse
path: textures/chain_texture.tga
- id: 18
type: texture_diffuse
path: textures/sponza_column_a_diff.tga
- id: 19
type: texture_diffuse
path: textures/sponza_column_b_diff.tga
- id: 20
type: texture_diffuse
path: textures/sponza_column_c_diff.tga
- id: 21
type: texture_diffuse
path: textures/sponza_details_diff.tga
- id: 22
type: texture_diffuse
path: textures/sponza_fabric_diff.tga
- id: 23
type: texture_diffuse
path: textures/sponza_curtain_diff.tga
- id: 24
type: texture_diffuse
path: textures/sponza_fabric_blue_diff.tga
- id: 25
type: texture_diffuse
path: textures/sponza_fabric_green_diff.tga
- id: 26
type: texture_diffuse
path: textures/sponza_curtain_green_diff.tga
- id: 27
type: texture_diffuse
path: textures/sponza_curtain_blue_diff.tga
- id: 28
type: texture_diffuse
path: textures/sponza_flagpole_diff.tga
- id: 29
type: texture_diffuse
path: textures/sponza_floor_a_diff.tga
- id: 30
type: texture_diffuse
path: textures/sponza_thorn_diff.tga
- id: 31
type: texture_diffuse
path: textures/sponza_roof_diff.tga
- id: 32
type: texture_diffuse
path: textures/vase_dif.tga
- id: 33
type: texture_diffuse
path: textures/vase_hanging.tga
- id: 34
type: texture_diffuse
path: textures/vase_round.tga
submeshes:
- vao: 3
indexCount: 43452
textures:
- id: 30
type: texture_diffuse
path: textures/sponza_roof_diff.tga
- vao: 4
indexCount: 27552
textures:
- id: 31
type: texture_diffuse
path: textures/vase_dif.tga
- vao: 5
indexCount: 33024
textures:
- id: 21
type: texture_diffuse
path: textures/sponza_fabric_diff.tga
- vao: 6
indexCount: 54
textures: ~
- vao: 7
indexCount: 12258
textures:
- id: 11
type: texture_diffuse
path: textures/background.tga
- vao: 8
indexCount: 10416
textures:
- id: 12
type: texture_diffuse
path: textures/vase_plant.tga
- vao: 9
indexCount: 49536
textures:
- id: 23
type: texture_diffuse
path: textures/sponza_fabric_blue_diff.tga
- vao: 10
indexCount: 94308
textures:
- id: 29
type: texture_diffuse
path: textures/sponza_thorn_diff.tga
- vao: 11
indexCount: 49536
textures:
- id: 24
type: texture_diffuse
path: textures/sponza_fabric_green_diff.tga
- vao: 12
indexCount: 17628
textures:
- id: 15
type: texture_diffuse
path: textures/sponza_ceiling_a_diff.tga
- vao: 13
indexCount: 30504
textures:
- id: 13
type: texture_diffuse
path: textures/sponza_arch_diff.tga
- vao: 14
indexCount: 53064
textures:
- id: 33
type: texture_diffuse
path: textures/vase_round.tga
- vao: 15
indexCount: 69624
textures:
- id: 18
type: texture_diffuse
path: textures/sponza_column_b_diff.tga
- vao: 16
indexCount: 2640
textures:
- id: 20
type: texture_diffuse
path: textures/sponza_details_diff.tga
- vao: 17
indexCount: 43008
textures:
- id: 26
type: texture_diffuse
path: textures/sponza_curtain_blue_diff.tga
- vao: 18
indexCount: 0
textures: ~
- vao: 19
indexCount: 2388
textures:
- id: 14
type: texture_diffuse
path: textures/spnza_bricks_a_diff.tga
- vao: 20
indexCount: 21264
textures:
- id: 19
type: texture_diffuse
path: textures/sponza_column_c_diff.tga
- vao: 21
indexCount: 63
textures:
- id: 28
type: texture_diffuse
path: textures/sponza_floor_a_diff.tga
- vao: 22
indexCount: 43008
textures:
- id: 25
type: texture_diffuse
path: textures/sponza_curtain_green_diff.tga
- vao: 23
indexCount: 9126
textures:
- id: 10
type: texture_diffuse
path: textures/lion.tga
- vao: 24
indexCount: 96
textures:
- id: 16
type: texture_diffuse
path: textures/chain_texture.tga
- vao: 25
indexCount: 56832
textures:
- id: 22
type: texture_diffuse
path: textures/sponza_curtain_diff.tga
- vao: 26
indexCount: 8448
textures:
- id: 17
type: texture_diffuse
path: textures/sponza_column_a_diff.tga
- vao: 27
indexCount: 49488
textures:
- id: 27
type: texture_diffuse
path: textures/sponza_flagpole_diff.tga
- vao: 28
indexCount: 59484
textures:
- id: 32
type: texture_diffuse
path: textures/vase_hanging.tga
MeshPath: assets/models/sponza.obj
ScriptComponent:
ScriptPath: ""
- ID: 1
Name: Gun
Components:
ScriptComponent:
ScriptPath: assets/scripts/BouncingItem.lua
Mesh:
vao: 5
indexCount: 116445
textures: ~
MeshPath: assets/models/AK-47.obj
Transform:
Position: [0, 9.54316807, -50]
Rotation: [0, 253.495804, 0]
Scale: [0.100000001, 0.100000001, 0.100000001]
ScriptPath: assets/scripts/BouncingItem.lua

View File

@ -10,7 +10,7 @@ extern AssetManager g_AssetManager;
const std::string MeshComponent::name = "Mesh";
MeshComponent::MeshComponent()
: vao(0), indexCount(0), MeshPath("assets/models/DefaultMesh.obj")
: MeshPath("assets/models/DefaultMesh.obj")
{
}
@ -26,29 +26,52 @@ const std::string &MeshComponent::GetStaticName()
void MeshComponent::Update(float deltaTime)
{
(void)deltaTime;
return;
}
void MeshComponent::Draw(Shader* shader)
{
for (auto &submesh : submeshes)
{
submesh.Draw(shader);
}
}
YAML::Node MeshComponent::Serialize()
{
YAML::Node node;
node["vao"] = static_cast<int>(vao);
node["indexCount"] = static_cast<int>(indexCount);
// Serialize Textures
YAML::Node texturesNode;
for (const auto &texture : textures)
{
YAML::Node texNode;
texNode["id"] = static_cast<int>(texture.id);
texNode["type"] = texture.type;
texNode["path"] = texture.path;
texturesNode.push_back(texNode);
}
node["textures"] = texturesNode;
// Serialize each submesh
node["MeshPath"] = MeshPath;
YAML::Node submeshesNode;
for (const auto &submesh : submeshes)
{
YAML::Node submeshNode;
submeshNode["vao"] = static_cast<int>(submesh.vao);
submeshNode["indexCount"] = static_cast<int>(submesh.indices.size());
// Serialize Textures
YAML::Node texturesNode;
for (const auto &texture : submesh.textures)
{
YAML::Node texNode;
texNode["id"] = static_cast<int>(texture.id);
texNode["type"] = texture.type;
texNode["path"] = texture.path;
texturesNode.push_back(texNode);
}
submeshNode["textures"] = texturesNode;
submeshesNode.push_back(submeshNode);
}
node["submeshes"] = submeshesNode;
return node;
}
@ -60,7 +83,7 @@ void MeshComponent::Deserialize(const YAML::Node &node)
DEBUG_PRINT("Loading Mesh: %s", MeshPath.c_str());
Model *model = g_AssetManager.loadAsset<Model *>(AssetType::MODEL, MeshPath.c_str());
std::shared_ptr<Model> model = g_AssetManager.loadAsset<Model>(AssetType::MODEL, MeshPath.c_str());
if (!model)
{
@ -68,67 +91,46 @@ void MeshComponent::Deserialize(const YAML::Node &node)
return;
}
DEBUG_PRINT("Model loaded successfully with %zu vertices and %zu indices.",
model->vertices.size(), model->indices.size());
DEBUG_PRINT("Model loaded successfully with %zu submeshes.", model->submeshes.size());
// Assign VAO and index count
if (model->vao != 0)
{
vao = model->vao;
}
else if (node["vao"])
{
vao = node["vao"].as<int>();
}
if (model->indices.size() != 0)
{
indexCount = static_cast<GLuint>(model->indices.size());
}
else if (node["indexCount"])
{
indexCount = node["indexCount"].as<int>();
}
// Assign Textures
if (!model->textures.empty())
{
textures = model->textures;
}
else if (node["textures"])
{
const YAML::Node &texturesNode = node["textures"];
for (const auto &texNode : texturesNode)
{
Texture texture;
texture.id = texNode["id"].as<int>();
texture.type = texNode["type"].as<std::string>();
texture.path = texNode["path"].as<std::string>();
textures.push_back(texture);
}
}
// Assign submeshes
submeshes = std::move(model->submeshes);
}
else
{
if (node["vao"])
// Handle cases where submeshes are stored directly
if (node["submeshes"])
{
vao = node["vao"].as<int>();
}
if (node["indexCount"])
{
indexCount = node["indexCount"].as<int>();
}
if (node["textures"])
{
const YAML::Node &texturesNode = node["textures"];
for (const auto &texNode : texturesNode)
const YAML::Node &submeshesNode = node["submeshes"];
for (const auto &submeshNode : submeshesNode)
{
Texture texture;
texture.id = texNode["id"].as<int>();
texture.type = texNode["type"].as<std::string>();
texture.path = texNode["path"].as<std::string>();
textures.push_back(texture);
Submesh submesh;
if (submeshNode["vao"])
{
submesh.vao = submeshNode["vao"].as<int>();
}
if (submeshNode["indexCount"])
{
submesh.indices.reserve(submeshNode["indexCount"].as<int>());
// Assuming indices are stored elsewhere or need to be loaded
}
if (submeshNode["textures"])
{
const YAML::Node &texturesNode = submeshNode["textures"];
for (const auto &texNode : texturesNode)
{
Texture texture;
texture.id = texNode["id"].as<int>();
texture.type = texNode["type"].as<std::string>();
texture.path = texNode["path"].as<std::string>();
submesh.textures.push_back(texture);
}
}
submeshes.push_back(std::move(submesh));
}
}
}
}
}

View File

@ -10,15 +10,18 @@
#include <string>
#include "Engine/AssetManager.h"
// In MeshComponent.h
class MeshComponent : public Component
{
public:
GLuint vao = 0; // Vertex Array Object
GLuint indexCount = 0; // Number of indices to draw
std::vector<Texture> textures; // List of textures associated with the mesh
std::vector<Submesh> submeshes; // List of submeshes
std::string MeshPath;
static const std::string name;
MeshComponent();
virtual const std::string& GetName() const override;
static const std::string& GetStaticName();
@ -29,6 +32,9 @@ public:
virtual YAML::Node Serialize() override;
virtual void Deserialize(const YAML::Node& node) override;
private:
static const std::string name;
// Render the mesh
void Draw(Shader* shader);
};

View File

@ -105,6 +105,11 @@ bool MyEngine::Init(int width, int height, const std::string &title)
(void)io;
// Enable docking
io.ConfigFlags |= ImGuiConfigFlags_DockingEnable;
#ifdef DEBUG
ImGui::GetIO().ConfigFlags |= ImGuiConfigFlags_DockingEnable | ImGuiConfigFlags_ViewportsEnable;
#endif
// (Optional) Multi-viewport
// io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable;
@ -148,35 +153,6 @@ void MyEngine::Run()
DEBUG_PRINT("[START] Engine Run ");
DEBUG_PRINT("Transition to Editor");
g_AssetManager.loadAsset<GLuint>(AssetType::TEXTURE, "assets/textures/bricks.png");
g_AssetManager.loadAsset<GLuint>(AssetType::TEXTURE, "assets/textures/default.png");
g_AssetManager.loadAsset<GLuint>(AssetType::TEXTURE, "assets/textures/lush_grass.png");
g_AssetManager.loadAsset<GLuint>(AssetType::TEXTURE, "assets/textures/vegetation_tree_bark_40.png");
g_AssetManager.loadAsset<GLuint>(AssetType::TEXTURE, "assets/textures/ak-47.jpg");
g_AssetManager.loadAsset<GLuint>(AssetType::TEXTURE, "assets/textures/sky.png");
// Load a model
Model *modelPtr = g_AssetManager.loadAsset<Model *>(AssetType::MODEL, "assets/models/LowPolyFiatUNO.obj");
if (modelPtr == nullptr)
{
DEBUG_PRINT("Failed to load model.");
}
else
{
Model *model = reinterpret_cast<Model *>(modelPtr);
DEBUG_PRINT("Model loaded successfully with %lld vertices and %lld indices.", model->vertices.size(), model->indices.size());
}
Model *modelPtr4 = g_AssetManager.loadAsset<Model *>(AssetType::MODEL, "assets/models/shopping-cart.obj");
Model *model4 = reinterpret_cast<Model *>(modelPtr4);
DEBUG_PRINT("Model loaded successfully with %lld vertices and %lld indices.", model4->vertices.size(), model4->indices.size());
DEBUG_PRINT("Put componenent into Global Componenets Subsystem");
// printf("%p\n", &g_GameObjects);
// Possibly create more GameObjects with different positions or textures
@ -224,7 +200,7 @@ void MyEngine::Run()
ScopedTimer timer("SaveScene");
m_FirstTickGameRunning = false;
std::string savePath = createTempFolder().string() + "TesseractEngineTempScene.scene";
std::string savePath = createTempFolder().string() + "/TesseractEngineTempScene.scene";
DEBUG_PRINT("Save path: %s", savePath.c_str());
g_SceneManager.SaveScene(g_GameObjects, savePath);
@ -249,7 +225,7 @@ void MyEngine::Run()
ScopedTimer timer("LoadScene");
m_FirstTickGameRunning = true;
std::string loadPath = createTempFolder().string() + "TesseractEngineTempScene.scene";
std::string loadPath = createTempFolder().string() + "/TesseractEngineTempScene.scene";
DEBUG_PRINT("Load path: %s", loadPath.c_str());

View File

@ -49,21 +49,44 @@ void AssetManager::DebugAssetMap()
}
}
// Implementation of AssetManager::loadAssetFromDisk
AssetManager::AssetVariant AssetManager::loadAssetFromDisk(AssetType type, const std::string &path)
{
//DebugAssetMap();
// DebugAssetMap();
g_LoggerWindow->AddLog("[AssetManager] Loading asset: %s", path.c_str());
LoadedAssets = m_AssetMap.size();
switch (type)
{
case AssetType::TEXTURE:
return LoadTextureFromList(path); // Returns GLuint
{
GLuint textureID = LoadTextureFromList(path); // Returns GLuint
return std::make_shared<GLuint>(textureID); // Wrap in shared_ptr
}
case AssetType::SHADER:
return LoadShaderFromList(path); // Returns Shader*
case AssetType::SOUND:
return std::string("Loaded sound: " + path); // Example placeholder for sound
{
Shader* shaderPtr = LoadShaderFromList(path); // Returns Shader*
if (shaderPtr != nullptr)
{
// It's essential to ensure that shaderPtr is dynamically allocated and not managed elsewhere
return std::shared_ptr<Shader>(shaderPtr);
}
else
{
throw std::runtime_error("Failed to load shader: " + path);
}
}
case AssetType::MODEL:
return LoadModelFromList(path); // Returns Model*
{
Model* modelPtr = LoadModelFromList(path); // Returns Model*
if (modelPtr != nullptr)
{
// It's essential to ensure that modelPtr is dynamically allocated and not managed elsewhere
return std::shared_ptr<Model>(modelPtr);
}
else
{
throw std::runtime_error("Failed to load model: " + path);
}
}
default:
throw std::invalid_argument("Unknown AssetType");
}
@ -79,13 +102,11 @@ GLuint LoadTextureFromList(const std::string &path)
// --------------------------------------------
// 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 0;
}
@ -118,32 +139,24 @@ GLuint LoadTextureFromList(const std::string &path)
return texID;
}
Shader *LoadShaderFromList(const std::string &path)
Shader* LoadShaderFromList(const std::string &path)
{
// --------------------------------------------
// 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))
// Create a new Shader object using the constructor that takes vertex and fragment paths
Shader *newShader = new Shader(vertPath.c_str(), fragPath.c_str());
// Check if shader compiled and linked successfully
if (newShader->ID == 0)
{
std::cerr << "[AssetManager] Could not load shader: "
<< vertPath << " / " << fragPath << std::endl;
delete newShader; // Cleanup
return nullptr;
}
// Return as void*
// Return the Shader pointer as void*
return newShader;
}
@ -160,7 +173,7 @@ GLuint LoadTexture(const std::string &path, const std::string &directory)
unsigned char *data = stbi_load(fullPath.c_str(), &width, &height, &channels, 0);
if (!data)
{
std::cerr << "[AssetManager] failed to load texture: " << fullPath << " " << stbi_failure_reason() << std::endl;
DEBUG_PRINT("[AssetManager] failed to load texture: %s: %s", fullPath.c_str(),stbi_failure_reason());
return 0;
}
@ -203,30 +216,16 @@ GLuint LoadTexture(const std::string &path, const std::string &directory)
Model* LoadModelFromList(const std::string &path)
{
// --------------------------------------------
// Load an OBJ model
// --------------------------------------------
std::cout << "[AssetManager] Loading MODEL from: " << path << std::endl;
std::ifstream objFile(path);
if (!objFile.is_open())
{
std::cerr << "[AssetManager] Failed to open OBJ file: " << path << std::endl;
return nullptr;
}
std::vector<float> temp_positions;
std::vector<float> temp_texCoords;
std::vector<float> temp_normals;
std::vector<unsigned int> vertexIndices, texCoordIndices, normalIndices;
// Preallocate vectors with estimated sizes for performance
temp_positions.reserve(1000);
temp_texCoords.reserve(500);
temp_normals.reserve(500);
vertexIndices.reserve(3000);
texCoordIndices.reserve(3000);
normalIndices.reserve(3000);
std::string directory;
size_t lastSlash = path.find_last_of("/\\");
@ -235,7 +234,12 @@ Model* LoadModelFromList(const std::string &path)
else
directory = "";
std::cout << "[AssetManager] Asset Directory: " << directory << std::endl;
std::string currentMaterial = "default";
// Map material name to Submesh
std::unordered_map<std::string, Submesh> materialToSubmesh;
materialToSubmesh[currentMaterial] = Submesh();
std::string line;
std::string mtlFileName;
@ -247,6 +251,7 @@ Model* LoadModelFromList(const std::string &path)
std::istringstream iss(line);
std::string prefix;
iss >> prefix;
if (prefix == "v")
{
float x, y, z;
@ -272,6 +277,18 @@ Model* LoadModelFromList(const std::string &path)
temp_normals.push_back(-ny); // Inverted
temp_normals.push_back(nz);
}
else if (prefix == "usemtl")
{
iss >> currentMaterial;
if (materialToSubmesh.find(currentMaterial) == materialToSubmesh.end())
{
materialToSubmesh[currentMaterial] = Submesh();
}
}
else if (prefix == "mtllib")
{
iss >> mtlFileName;
}
else if (prefix == "f")
{
std::string vertexStr;
@ -313,38 +330,75 @@ Model* LoadModelFromList(const std::string &path)
// Triangulate if the face has more than 3 vertices
for (size_t i = 1; i + 1 < faceVertices.size(); ++i)
{
vertexIndices.push_back(std::get<0>(faceVertices[0]));
texCoordIndices.push_back(std::get<1>(faceVertices[0]));
normalIndices.push_back(std::get<2>(faceVertices[0]));
// Current material's submesh
Submesh &currentSubmesh = materialToSubmesh[currentMaterial];
vertexIndices.push_back(std::get<0>(faceVertices[i]));
texCoordIndices.push_back(std::get<1>(faceVertices[i]));
normalIndices.push_back(std::get<2>(faceVertices[i]));
auto addVertex = [&](unsigned int v, unsigned int t, unsigned int n) -> unsigned int {
Vertex vertex;
// OBJ indices are 1-based
vertex.position[0] = temp_positions[(v - 1) * 3];
vertex.position[1] = temp_positions[(v - 1) * 3 + 1];
vertex.position[2] = temp_positions[(v - 1) * 3 + 2];
vertexIndices.push_back(std::get<0>(faceVertices[i + 1]));
texCoordIndices.push_back(std::get<1>(faceVertices[i + 1]));
normalIndices.push_back(std::get<2>(faceVertices[i + 1]));
if (!temp_texCoords.empty() && t > 0)
{
vertex.texCoord[0] = temp_texCoords[(t - 1) * 2];
vertex.texCoord[1] = temp_texCoords[(t - 1) * 2 + 1];
}
else
{
vertex.texCoord[0] = 0.0f;
vertex.texCoord[1] = 0.0f;
}
if (!temp_normals.empty() && n > 0)
{
vertex.normal[0] = temp_normals[(n - 1) * 3];
vertex.normal[1] = temp_normals[(n - 1) * 3 + 1];
vertex.normal[2] = temp_normals[(n - 1) * 3 + 2];
}
else
{
vertex.normal[0] = 0.0f;
vertex.normal[1] = 0.0f;
vertex.normal[2] = 0.0f;
}
// Check if the vertex already exists in the submesh
auto it = std::find(currentSubmesh.vertices.begin(), currentSubmesh.vertices.end(), vertex);
if (it != currentSubmesh.vertices.end())
{
return static_cast<unsigned int>(std::distance(currentSubmesh.vertices.begin(), it));
}
else
{
currentSubmesh.vertices.push_back(vertex);
return static_cast<unsigned int>(currentSubmesh.vertices.size() - 1);
}
};
unsigned int idx0 = addVertex(std::get<0>(faceVertices[0]), std::get<1>(faceVertices[0]), std::get<2>(faceVertices[0]));
unsigned int idx1 = addVertex(std::get<0>(faceVertices[i]), std::get<1>(faceVertices[i]), std::get<2>(faceVertices[i]));
unsigned int idx2 = addVertex(std::get<0>(faceVertices[i + 1]), std::get<1>(faceVertices[i + 1]), std::get<2>(faceVertices[i + 1]));
currentSubmesh.indices.push_back(idx0);
currentSubmesh.indices.push_back(idx1);
currentSubmesh.indices.push_back(idx2);
}
}
else if (prefix == "mtllib")
{
iss >> mtlFileName;
}
}
objFile.close();
// Load MTL file if specified
std::vector<Texture> textures;
std::unordered_map<std::string, std::vector<Texture>> materialTexturesMap;
if (!mtlFileName.empty())
{
std::ifstream mtlFile(directory + mtlFileName);
if (mtlFile.is_open())
{
std::string mtlLine;
std::string currentMaterial;
std::unordered_map<std::string, std::string> materialTextures;
std::string currentMaterialName;
while (std::getline(mtlFile, mtlLine))
{
if (mtlLine.empty() || mtlLine[0] == '#')
@ -356,7 +410,7 @@ Model* LoadModelFromList(const std::string &path)
if (mtlPrefix == "newmtl")
{
mtlIss >> currentMaterial;
mtlIss >> currentMaterialName;
}
else if (mtlPrefix == "map_Kd")
{
@ -371,7 +425,7 @@ Model* LoadModelFromList(const std::string &path)
texture.id = texID;
texture.type = "texture_diffuse";
texture.path = texturePath;
textures.push_back(texture);
materialTexturesMap[currentMaterialName].push_back(texture);
}
}
}
@ -388,7 +442,7 @@ Model* LoadModelFromList(const std::string &path)
texture.id = texID;
texture.type = "texture_specular";
texture.path = texturePath;
textures.push_back(texture);
materialTexturesMap[currentMaterialName].push_back(texture);
}
}
}
@ -405,7 +459,7 @@ Model* LoadModelFromList(const std::string &path)
texture.id = texID;
texture.type = "texture_normal";
texture.path = texturePath;
textures.push_back(texture);
materialTexturesMap[currentMaterialName].push_back(texture);
}
}
}
@ -416,110 +470,47 @@ Model* LoadModelFromList(const std::string &path)
}
else
{
std::cerr << "[AssetManager] Failed to open MTL file: " << mtlFileName << std::endl;
}
}
else
{
std::cout << "[AssetManager] No MTL file specified for OBJ: " << path << std::endl;
}
if (textures.empty())
// Assign textures to submeshes based on their material
for (auto &pair : materialToSubmesh)
{
std::cout << "[AssetManager] No textures found for OBJ: " << path << std::endl;
const std::string &materialName = pair.first;
Submesh &submesh = pair.second;
if (materialTexturesMap.find(materialName) != materialTexturesMap.end())
{
submesh.textures = materialTexturesMap[materialName];
}
else
{
// If no material textures found, you can assign default textures or leave it empty
}
// Initialize OpenGL buffers for the submesh
submesh.Initialize();
}
else
if (materialToSubmesh.empty())
{
std::cout << "[AssetManager] Loaded " << textures.size() << " textures for OBJ: " << path << std::endl;
return nullptr;
}
// Create Model object
Model *model = new Model();
model->textures = textures;
// Populate vertices with unique vertices
std::unordered_map<std::string, unsigned int> uniqueVertices;
uniqueVertices.reserve(vertexIndices.size());
model->vertices.reserve(vertexIndices.size());
model->indices.reserve(vertexIndices.size());
for (size_t i = 0; i < vertexIndices.size(); ++i)
// Move submeshes to the model
for (auto &pair : materialToSubmesh)
{
std::ostringstream keyStream;
keyStream << vertexIndices[i] << "/" << texCoordIndices[i] << "/" << normalIndices[i];
std::string key = keyStream.str();
auto it = uniqueVertices.find(key);
if (it == uniqueVertices.end())
{
Vertex vertex;
// OBJ indices are 1-based
vertex.position[0] = temp_positions[(vertexIndices[i] - 1) * 3];
vertex.position[1] = temp_positions[(vertexIndices[i] - 1) * 3 + 1];
vertex.position[2] = temp_positions[(vertexIndices[i] - 1) * 3 + 2];
if (!temp_texCoords.empty() && texCoordIndices[i] > 0)
{
vertex.texCoord[0] = temp_texCoords[(texCoordIndices[i] - 1) * 2];
vertex.texCoord[1] = temp_texCoords[(texCoordIndices[i] - 1) * 2 + 1];
}
else
{
vertex.texCoord[0] = 0.0f;
vertex.texCoord[1] = 0.0f;
}
if (!temp_normals.empty() && normalIndices[i] > 0)
{
vertex.normal[0] = temp_normals[(normalIndices[i] - 1) * 3];
vertex.normal[1] = temp_normals[(normalIndices[i] - 1) * 3 + 1];
vertex.normal[2] = temp_normals[(normalIndices[i] - 1) * 3 + 2];
}
else
{
vertex.normal[0] = 0.0f;
vertex.normal[1] = 0.0f;
vertex.normal[2] = 0.0f;
}
model->vertices.push_back(vertex);
unsigned int newIndex = static_cast<unsigned int>(model->vertices.size() - 1);
uniqueVertices[key] = newIndex;
model->indices.push_back(newIndex);
}
else
{
model->indices.push_back(it->second);
}
model->submeshes.emplace_back(std::move(pair.second));
}
// Generate OpenGL buffers
glGenVertexArrays(1, &model->vao);
glGenBuffers(1, &model->vbo);
glGenBuffers(1, &model->ebo);
DEBUG_PRINT("[AssetManager] Loaded model with %lld submeshes.", model->submeshes.size());
glBindVertexArray(model->vao);
glBindBuffer(GL_ARRAY_BUFFER, model->vbo);
glBufferData(GL_ARRAY_BUFFER, model->vertices.size() * sizeof(Vertex), model->vertices.data(), GL_STATIC_DRAW);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, model->ebo);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, model->indices.size() * sizeof(unsigned int), model->indices.data(), GL_STATIC_DRAW);
// Vertex positions
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)0);
// Texture coordinates
glEnableVertexAttribArray(1);
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)(3 * sizeof(float)));
// Normals
glEnableVertexAttribArray(2);
glVertexAttribPointer(2, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)(5 * sizeof(float)));
glBindVertexArray(0);
// The textures are already loaded and stored in the model->textures vector
return model;
}
}

View File

@ -2,12 +2,17 @@
#include <string>
#include <unordered_map>
#include <map>
#include <GL/glew.h>
#include <vector>
#include <variant>
#include "gcml.h"
#include "stdexcept"
#include <iostream>
#include "Rendering/Shader.h"
#include <algorithm>
#include <cmath> // For std::abs
#include <memory>
// Forward-declare your Shader class
class Shader;
@ -32,20 +37,144 @@ struct Vertex
float position[3];
float texCoord[2];
float normal[3];
// Equality operator to compare two Vertex instances
bool operator==(const Vertex &other) const
{
// Compare positions
for (int i = 0; i < 3; ++i)
{
if (position[i] != other.position[i])
return false;
}
// Compare texture coordinates
for (int i = 0; i < 2; ++i)
{
if (texCoord[i] != other.texCoord[i])
return false;
}
// Compare normals
for (int i = 0; i < 3; ++i)
{
if (normal[i] != other.normal[i])
return false;
}
return true;
}
};
// Define a Texture structure
struct Texture {
struct Texture
{
GLuint id;
std::string type;
std::string path;
};
struct Model {
// In AssetManager.h or a separate header file
struct Submesh
{
std::vector<Vertex> vertices;
std::vector<unsigned int> indices;
std::vector<Texture> textures;
GLuint vao, vbo, ebo;
GLuint vao = 0, vbo = 0, ebo = 0;
// Initialize OpenGL buffers for the submesh
void Initialize()
{
glGenVertexArrays(1, &vao);
glGenBuffers(1, &vbo);
glGenBuffers(1, &ebo);
glBindVertexArray(vao);
glBindBuffer(GL_ARRAY_BUFFER, vbo);
glBufferData(GL_ARRAY_BUFFER, vertices.size() * sizeof(Vertex), vertices.data(), GL_STATIC_DRAW);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ebo);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, indices.size() * sizeof(unsigned int), indices.data(), GL_STATIC_DRAW);
// Vertex positions
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void *)0);
// Texture coordinates
glEnableVertexAttribArray(1);
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void *)(3 * sizeof(float)));
// Normals
glEnableVertexAttribArray(2);
glVertexAttribPointer(2, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void *)(5 * sizeof(float)));
glBindVertexArray(0);
}
// Render the submesh
void Draw(Shader *shader)
{
// Bind appropriate textures
unsigned int diffuseNr = 1;
unsigned int specularNr = 1;
unsigned int normalNr = 1;
for (unsigned int i = 0; i < textures.size(); i++)
{
glActiveTexture(GL_TEXTURE0 + i); // Activate proper texture unit before binding
// Retrieve texture number (the N in diffuse_textureN)
std::string number;
std::string name = textures[i].type;
if (name == "texture_diffuse")
number = std::to_string(diffuseNr++);
else if (name == "texture_specular")
number = std::to_string(specularNr++);
else if (name == "texture_normal")
number = std::to_string(normalNr++);
// Now set the sampler to the correct texture unit
shader->SetInt((name + number).c_str(), i);
glBindTexture(GL_TEXTURE_2D, textures[i].id);
}
// Draw mesh
glBindVertexArray(vao);
glDrawElements(GL_TRIANGLES, static_cast<GLsizei>(indices.size()), GL_UNSIGNED_INT, 0);
glBindVertexArray(0);
// Always good practice to set everything back to defaults once configured.
glActiveTexture(GL_TEXTURE0);
}
};
// In AssetManager.h or a separate header file
struct Model
{
std::vector<Submesh> submeshes;
// Render all submeshes
void Draw(Shader *shader)
{
for (auto &submesh : submeshes)
{
submesh.Draw(shader);
}
}
// Cleanup OpenGL resources
void Cleanup()
{
for (auto &submesh : submeshes)
{
if (submesh.vao != 0)
glDeleteVertexArrays(1, &submesh.vao);
if (submesh.vbo != 0)
glDeleteBuffers(1, &submesh.vbo);
if (submesh.ebo != 0)
glDeleteBuffers(1, &submesh.ebo);
}
}
};
// The main AssetManager
@ -55,11 +184,11 @@ public:
AssetManager() = default;
~AssetManager() = default;
using AssetVariant = std::variant<GLuint, Shader *, std::string, Model *>;
using AssetVariant = std::variant<std::shared_ptr<Model>, std::shared_ptr<Shader>, std::shared_ptr<GLuint>>;
// Template function to load an asset
template <typename T>
T loadAsset(AssetType type, const std::string &path)
std::shared_ptr<T> loadAsset(AssetType type, const std::string &path)
{
// 1) Create a unique key for cache lookup
std::string key = generateKey(type, path);
@ -69,9 +198,13 @@ public:
if (it != m_AssetMap.end())
{
// Debug: Log the variant type
if (std::holds_alternative<T>(it->second))
if (std::holds_alternative<std::shared_ptr<T>>(it->second))
{
return std::get<T>(it->second);
#ifdef DEBUG
DebugAssetMap();
#endif
std::cout << "[AssetManager] Retrieved asset from cache: " << key << std::endl;
return std::get<std::shared_ptr<T>>(it->second);
}
else
{
@ -79,36 +212,27 @@ public:
}
}
// 3) Not loaded yet, load from disk
// 3) Not loaded yet
AssetVariant assetData = loadAssetFromDisk(type, path);
if (assetData.index() == std::variant_npos)
if (assetData.valueless_by_exception())
{
DEBUG_PRINT("[AssetManager] Failed to load asset: %s", path.c_str());
// Replace NULL with 0 for non-pointer types
if constexpr (std::is_pointer_v<T>)
{
return nullptr; // For pointers
}
else
{
return 0; // For non-pointer
}
return nullptr; // For smart pointers, return nullptr on failure
}
// 4) Store in cache
m_AssetMap[key] = assetData;
// 5) Return the loaded asset
return std::get<T>(assetData);
return std::get<std::shared_ptr<T>>(assetData);
}
void DebugAssetMap();
private:
// Cache of already loaded assets: key = "type + path"
std::unordered_map<std::string, AssetVariant> m_AssetMap;
std::map<std::string, AssetVariant> m_AssetMap;
AssetVariant loadAssetFromDisk(AssetType type, const std::string &path);
// Generate the unique key

View File

@ -1,95 +1,145 @@
// Shader.cpp
#include "Shader.h"
#include <fstream>
#include <sstream>
#include <iostream>
#include <glm/gtc/type_ptr.hpp> // For glm::value_ptr
// Constructor implementations
Shader::Shader() : ID(0) {}
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)
{
std::cerr << "ERROR::SHADER::FILE_NOT_SUCCESSFULLY_READ: " << e.what() << std::endl;
}
const char* vShaderCode = vertexCode.c_str();
const char * fShaderCode = fragmentCode.c_str();
// 2. Compile shaders
GLuint vertex, fragment;
GLint success;
GLchar 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);
std::cerr << "ERROR::SHADER::VERTEX::COMPILATION_FAILED\n" << infoLog << std::endl;
}
// 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);
std::cerr << "ERROR::SHADER::FRAGMENT::COMPILATION_FAILED\n" << infoLog << std::endl;
}
// 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);
std::cerr << "ERROR::SHADER::PROGRAM::LINKING_FAILED\n" << infoLog << std::endl;
}
// Delete the shaders as they're linked into our program now and no longer necessary
glDeleteShader(vertex);
glDeleteShader(fragment);
}
Shader::~Shader()
{
if (m_ProgramID)
glDeleteProgram(m_ProgramID);
glDeleteProgram(ID);
}
bool Shader::Load(const std::string& vertexPath, const std::string& fragmentPath)
void Shader::Use()
{
// 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;
glUseProgram(ID);
}
bool Shader::CompileShader(GLuint shaderID, const std::string& filePath)
GLint Shader::GetUniformLocation(const std::string &name) const
{
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;
// Check if the location is already cached
if (uniformLocationCache.find(name) != uniformLocationCache.end())
return uniformLocationCache.at(name);
// Otherwise, query it
GLint location = glGetUniformLocation(ID, name.c_str());
if (location == -1)
std::cerr << "Warning: uniform '" << name << "' doesn't exist or is not used in shader!" << std::endl;
// Cache the location
uniformLocationCache[name] = location;
return location;
}
std::string Shader::LoadSourceFromFile(const std::string& filePath)
void Shader::SetInt(const std::string &name, int value) const
{
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();
glUseProgram(ID); // Ensure the shader program is active
glUniform1i(GetUniformLocation(name), value);
}
void Shader::SetFloat(const std::string &name, float value) const
{
glUseProgram(ID); // Ensure the shader program is active
glUniform1f(GetUniformLocation(name), value);
}
void Shader::SetBool(const std::string &name, bool value) const
{
glUseProgram(ID); // Ensure the shader program is active
glUniform1i(GetUniformLocation(name), static_cast<int>(value));
}
void Shader::SetMat4(const std::string &name, const glm::mat4 &mat) const
{
glUseProgram(ID); // Ensure the shader program is active
glUniformMatrix4fv(GetUniformLocation(name), 1, GL_FALSE, glm::value_ptr(mat));
}

View File

@ -1,25 +1,34 @@
// Shader.h
#pragma once
#include <string>
#include <GL/glew.h>
#include <unordered_map>
#include <GL/glew.h> // or appropriate OpenGL headers
#include <glm/glm.hpp> // For glm::mat4
class Shader
{
public:
Shader() = default;
~Shader();
GLuint ID;
// Load & compile from files (vertex & fragment)
bool Load(const std::string& vertexPath, const std::string& fragmentPath);
// Constructors
Shader();
Shader(const char* vertexPath, const char* fragmentPath);
~Shader(); // Destructor to clean up shader program
void Use() const { glUseProgram(m_ProgramID); }
// Use/activate the shader
void Use();
// Uniform helper
GLuint GetProgramID() const { return m_ProgramID; }
// Utility functions to set uniforms
void SetInt(const std::string &name, int value) const;
void SetFloat(const std::string &name, float value) const;
void SetBool(const std::string &name, bool value) const;
void SetMat4(const std::string &name, const glm::mat4 &mat) const; // For setting 4x4 matrices
private:
bool CompileShader(GLuint shaderID, const std::string& source);
std::string LoadSourceFromFile(const std::string& filePath);
// Caching uniform locations for performance
mutable std::unordered_map<std::string, GLint> uniformLocationCache;
private:
GLuint m_ProgramID = 0;
// Retrieves the location of a uniform variable, with caching
GLint GetUniformLocation(const std::string &name) const;
};

View File

@ -10,6 +10,8 @@ extern std::vector<GameObject> g_GameObjects;
extern GameObject *g_SelectedObject; // Pointer to the currently selected object
extern std::shared_ptr<CameraComponent> g_RuntimeCameraObject;
#include "Engine/AssetManager.h"
extern AssetManager *g_AssetManager;
extern LoggerWindow *g_LoggerWindow;
void InspectorWindow::Show()
@ -535,27 +537,16 @@ void InspectorWindow::Show()
if (mesh && g_SelectedObject)
{
// Set text color to white for visibility
ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(1.0f, 1.0f, 1.0f, 1.0f));
// Create a collapsing header for the MeshComponent
bool meshOpen = ImGui::CollapsingHeader("Mesh##Main", ImGuiTreeNodeFlags_DefaultOpen);
ImGui::PopStyleColor();
if (meshOpen)
{
// --- VAO ---
int vao = static_cast<int>(mesh->vao);
if (ImGui::InputInt("VAO", &vao, 1, 0))
{
mesh->vao = static_cast<GLuint>(vao);
}
// --- Index Count ---
int indexCount = static_cast<int>(mesh->indexCount);
if (ImGui::InputInt("Index Count", &indexCount, 1, 0))
{
mesh->indexCount = static_cast<GLuint>(indexCount);
}
// --- Mesh Path ---
// --- Mesh Path (Editable) ---
const size_t BUFFER_SIZE = 256;
char buffer[BUFFER_SIZE];
strncpy(buffer, mesh->MeshPath.c_str(), BUFFER_SIZE - 1);
@ -565,100 +556,79 @@ void InspectorWindow::Show()
{
mesh->MeshPath = buffer;
// Optionally, trigger reloading the mesh if the path changes
// e.g., g_AssetManager.loadAsset<Model *>(AssetType::MODEL, mesh->MeshPath.c_str());
// Example:
std::shared_ptr<Model> model = g_AssetManager->loadAsset<Model>(AssetType::MODEL, mesh->MeshPath.c_str());
}
// --- Textures ---
// --- Submeshes Information ---
ImGui::Separator();
ImGui::Text("Textures:");
ImGui::Text("Submeshes:");
// Display list of textures
float availableWidth = ImGui::GetContentRegionAvail().x;
for (size_t i = 0; i < mesh->textures.size(); ++i)
// Check if the model is loaded
if (mesh)
{
Texture &texture = mesh->textures[i];
// Create a unique identifier for each texture section
std::string header = "Texture " + std::to_string(i + 1) + "##" + std::to_string(i);
// Collapsing header for each texture
if (ImGui::CollapsingHeader(header.c_str(), ImGuiTreeNodeFlags_DefaultOpen))
// Iterate through each Submesh
for (size_t sm = 0; sm < mesh->submeshes.size(); ++sm)
{
// --- Texture Type ---
char typeBuffer[32];
strncpy(typeBuffer, texture.type.c_str(), sizeof(typeBuffer) - 1);
typeBuffer[sizeof(typeBuffer) - 1] = '\0';
const Submesh &submesh = mesh->submeshes[sm];
std::string header = "Submesh " + std::to_string(sm + 1) + "##Submesh" + std::to_string(sm);
if (ImGui::InputText(("Type##" + std::to_string(i)).c_str(), typeBuffer, sizeof(typeBuffer)))
// Create a collapsing header for each Submesh
if (ImGui::CollapsingHeader(header.c_str(), ImGuiTreeNodeFlags_DefaultOpen))
{
texture.type = std::string(typeBuffer);
// Optionally, validate the type or restrict it to certain values
}
// --- Submesh VAO (Read-Only) ---
ImGui::Text("VAO: %d", static_cast<int>(submesh.vao));
// --- Texture ID ---
int texID = static_cast<int>(texture.id);
if (ImGui::InputInt(("Texture ID##" + std::to_string(i)).c_str(), &texID, 1, 0))
{
texture.id = static_cast<GLuint>(texID);
}
// --- Submesh Index Count (Read-Only) ---
ImGui::Text("Index Count: %d", static_cast<int>(submesh.indices.size()));
// --- Texture Path ---
char pathBuffer[256];
strncpy(pathBuffer, texture.path.c_str(), sizeof(pathBuffer) - 1);
pathBuffer[sizeof(pathBuffer) - 1] = '\0';
// --- Textures Associated with the Submesh ---
ImGui::Separator();
ImGui::Text("Textures:");
if (ImGui::InputText(("Path##" + std::to_string(i)).c_str(), pathBuffer, sizeof(pathBuffer)))
{
texture.path = std::string(pathBuffer);
// Optionally, trigger reloading the texture if the path changes
// e.g., texture.id = g_AssetManager.loadTexture(texture.path, directory);
}
// Iterate through each Texture in the Submesh
for (size_t i = 0; i < submesh.textures.size(); ++i)
{
const Texture &texture = submesh.textures[i];
std::string texHeader = "Texture " + std::to_string(i + 1) + "##Submesh" + std::to_string(sm) + "_Texture" + std::to_string(i);
// --- Texture Preview ---
if (texture.id != 0)
{
// Retrieve the texture's width and height if needed
// For demonstration, using a fixed size
ImGui::Image(static_cast<ImTextureID>(texture.id), ImVec2(availableWidth, availableWidth), ImVec2(0, 0), ImVec2(1, 1));
}
else
{
ImGui::Text("No texture bound.");
}
// Create a collapsing header for each Texture
if (ImGui::CollapsingHeader(texHeader.c_str(), ImGuiTreeNodeFlags_DefaultOpen))
{
// --- Texture Type (Read-Only) ---
ImGui::Text("Type: %s", texture.type.c_str());
// --- Remove Texture Button ---
std::string removeButtonLabel = "Remove##" + std::to_string(i);
if (ImGui::Button(removeButtonLabel.c_str()))
{
mesh->textures.erase(mesh->textures.begin() + i);
// Adjust index after removal
ImGui::TreePop();
break; // Exit the loop as the current index is invalidated
}
// --- Texture ID (Read-Only) ---
ImGui::Text("Texture ID: %d", static_cast<int>(texture.id));
ImGui::Separator();
// --- Texture Path (Read-Only) ---
ImGui::Text("Path: %s", texture.path.c_str());
// --- Texture Preview ---
if (texture.id != 0)
{
// Adjust the size as needed
ImVec2 imageSize = ImVec2(100, 100); // Example size
ImGui::Image(static_cast<ImTextureID>(texture.id), imageSize, ImVec2(0, 0), ImVec2(1, 1));
}
else
{
ImGui::Text("No texture bound.");
}
ImGui::Separator();
}
}
ImGui::Separator();
}
}
}
// --- Add New Texture Button ---
// if (ImGui::Button("Add Texture"))
//{
// // Define default values for the new texture
// Texture newTexture;
// newTexture.id = 0; // Assign a default or invalid texture ID
// newTexture.type = "texture_diffuse"; // Default type
// newTexture.path = "path/to/texture.png"; // Default path
//
// mesh->textures.push_back(newTexture);
//}
//
// --- Display All Textures ---
// Optionally, display all textures in a separate section or after the list
else
{
ImGui::TextColored(ImVec4(1.0f, 0.0f, 0.0f, 1.0f), "No model loaded.");
}
}
}

View File

@ -10,24 +10,22 @@ ProfilerWindow::ProfilerWindow()
{
// Initialize m_LastUpdateTime to force an immediate update on the first frame
m_LastUpdateTime = std::chrono::steady_clock::now() - std::chrono::duration_cast<std::chrono::steady_clock::duration>(std::chrono::duration<double>(m_UpdateInterval));
}
std::vector<float> ProfilerWindow::ExponentialMovingAverage(const std::deque<double>& data, float alpha) {
std::vector<float> ProfilerWindow::ExponentialMovingAverage(const std::deque<double> &data, float alpha)
{
std::vector<float> ema;
ema.reserve(data.size());
float prev = 0.0f;
for (const auto& val : data) {
for (const auto &val : data)
{
prev = alpha * static_cast<float>(val) + (1.0f - alpha) * prev;
ema.push_back(prev);
}
return ema;
}
void ProfilerWindow::UpdateHistory(const std::unordered_map<std::string, ProfileResult>& data, double totalFrameTime)
void ProfilerWindow::UpdateHistory(const std::unordered_map<std::string, ProfileResult> &data, double totalFrameTime)
{
// Update total frame time history
m_TotalFrameTimeHistory.push_back(totalFrameTime);
@ -35,9 +33,9 @@ void ProfilerWindow::UpdateHistory(const std::unordered_map<std::string, Profile
m_TotalFrameTimeHistory.pop_front();
// Update each function's profiling history
for (const auto& [name, result] : data)
for (const auto &[name, result] : data)
{
auto& history = m_ProfileHistories[name];
auto &history = m_ProfileHistories[name];
// Update total time history
history.totalTimeHistory.push_back(result.TotalTime);
@ -57,7 +55,7 @@ void ProfilerWindow::UpdateHistory(const std::unordered_map<std::string, Profile
}
// Ensure that functions not present in the current frame retain their last TotalTime and AverageTime
for (auto& [name, history] : m_ProfileHistories)
for (auto &[name, history] : m_ProfileHistories)
{
if (data.find(name) == data.end())
{
@ -102,7 +100,7 @@ void ProfilerWindow::Show()
// Begin ImGui window with improved styling
ImGui::Begin("Profiler", nullptr, ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_HorizontalScrollbar);
const auto& data = Profiler::Get().GetLastFrameData();
const auto &data = Profiler::Get().GetLastFrameData();
if (data.empty())
{
@ -115,7 +113,7 @@ void ProfilerWindow::Show()
{
// Calculate total frame time
double totalFrameTime = 0.0;
for (const auto& [name, result] : data)
for (const auto &[name, result] : data)
{
totalFrameTime += result.TotalTime;
}
@ -151,9 +149,10 @@ void ProfilerWindow::RenderTable()
// Sort functions by last Total Time descending
std::sort(allData.begin(), allData.end(),
[](const std::pair<std::string, ProfileHistory>& a, const std::pair<std::string, ProfileHistory>& b) -> bool {
return a.second.totalTimeHistory.back() > b.second.totalTimeHistory.back();
});
[](const std::pair<std::string, ProfileHistory> &a, const std::pair<std::string, ProfileHistory> &b) -> bool
{
return a.second.totalTimeHistory.back() > b.second.totalTimeHistory.back();
});
// Add a filter input with enhanced styling
ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(4, 2));
@ -166,7 +165,7 @@ void ProfilerWindow::RenderTable()
// Filtered data
std::vector<std::pair<std::string, ProfileHistory>> filteredData;
for (const auto& [name, history] : allData)
for (const auto &[name, history] : allData)
{
if (filterStr.empty() || name.find(filterStr) != std::string::npos)
filteredData.emplace_back(name, history);
@ -188,7 +187,7 @@ void ProfilerWindow::RenderTable()
// Alternate row colors for better readability
bool rowBg = false;
for (const auto& [name, history] : filteredData)
for (const auto &[name, history] : filteredData)
{
ImGui::TableNextRow();
rowBg = !rowBg;
@ -236,9 +235,10 @@ void ProfilerWindow::RenderGraphs()
// Collect and sort functions by last Total Time descending
std::vector<std::pair<std::string, ProfileHistory>> sortedData(m_ProfileHistories.begin(), m_ProfileHistories.end());
std::sort(sortedData.begin(), sortedData.end(),
[](const std::pair<std::string, ProfileHistory>& a, const std::pair<std::string, ProfileHistory>& b) -> bool {
return a.second.totalTimeHistory.back() > b.second.totalTimeHistory.back();
});
[](const std::pair<std::string, ProfileHistory> &a, const std::pair<std::string, ProfileHistory> &b) -> bool
{
return a.second.totalTimeHistory.back() > b.second.totalTimeHistory.back();
});
size_t displayCount = std::min<size_t>(5, sortedData.size()); // Limit to top 5 functions
@ -249,7 +249,7 @@ void ProfilerWindow::RenderGraphs()
float alpha = 0.2f; // Smoothing factor for EMA
for (size_t i = 0; i < displayCount; ++i)
{
const auto& [name, history] = sortedData[i];
const auto &[name, history] = sortedData[i];
functionNames.push_back(name);
// Smooth each function's data using EMA
@ -259,7 +259,7 @@ void ProfilerWindow::RenderGraphs()
// Find the longest data series and the maximum value for normalization
size_t maxHistorySize = 0;
float maxValue = 0.0f;
for (const auto& series : plotData)
for (const auto &series : plotData)
{
if (!series.empty())
{
@ -289,8 +289,7 @@ void ProfilerWindow::RenderGraphs()
nullptr,
0.0f,
static_cast<float>(maxValue) * 1.1f, // Add some padding to the max value
ImVec2(0, 100)
);
ImVec2(0, 100));
ImGui::PopStyleColor();
}

View File

@ -309,14 +309,14 @@ void RenderWindow::InitGLResources()
// ----------------------------------------------------
{
Shader *shaderAsset = g_AssetManager.loadAsset<Shader *>(AssetType::SHADER, "assets/shaders/UnlitMaterial");
std::shared_ptr<Shader> shaderAsset = g_AssetManager.loadAsset<Shader>(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);
m_ShaderPtr = shaderAsset.get();
}
// ----------------------------------------------------
@ -348,7 +348,7 @@ void RenderWindow::InitGLResources()
// 3) Load TEXTURE from the asset manager
// ----------------------------------------------------
{
GLuint texAsset = g_AssetManager.loadAsset<GLuint>(AssetType::TEXTURE, "assets/textures/wood.png");
std::shared_ptr<GLuint> texAsset = g_AssetManager.loadAsset<GLuint>(AssetType::TEXTURE, "assets/textures/wood.png");
if (!texAsset)
{
fprintf(stderr, "[RenderWindow] Failed to load texture.\n");
@ -356,7 +356,7 @@ void RenderWindow::InitGLResources()
else
{
// Cast from void* to GLuint
m_TextureID = texAsset;
m_TextureID = *texAsset; // Assign the GLuint value
}
}
@ -384,6 +384,11 @@ void CheckOpenGLError(const std::string &location)
#include <glm/gtc/type_ptr.hpp> // For glm::value_ptr
#include <algorithm> // Ensure <algorithm> is included
void RenderWindow::RenderSceneToFBO(bool *GameRunning)
{
m_RotationAngle += 0.001f; // Spin per frame
@ -406,7 +411,6 @@ void RenderWindow::RenderSceneToFBO(bool *GameRunning)
}
m_ShaderPtr->Use();
GLuint programID = m_ShaderPtr->GetProgramID();
// Define view and projection matrices once
std::shared_ptr<CameraComponent> activeCamera = nullptr;
@ -442,18 +446,8 @@ void RenderWindow::RenderSceneToFBO(bool *GameRunning)
std::shared_ptr<TransformComponent> transform = obj->GetComponent<TransformComponent>();
std::shared_ptr<MeshComponent> mesh = obj->GetComponent<MeshComponent>();
if (transform && mesh)
if (transform && mesh && mesh)
{
// Validate VAO
if (mesh->vao == 0)
{
DEBUG_PRINT("[RenderWindow] Warning: Mesh VAO is not initialized.");
continue;
}
// Update triangle count
g_GPU_Triangles_drawn_to_screen += static_cast<int>(mesh->indexCount);
// Apply transformations
model = glm::translate(model, transform->position);
model = glm::rotate(model, glm::radians(transform->rotation.x), glm::vec3(1.f, 0.f, 0.f));
@ -461,108 +455,78 @@ void RenderWindow::RenderSceneToFBO(bool *GameRunning)
model = glm::rotate(model, glm::radians(transform->rotation.z), glm::vec3(0.f, 0.f, 1.f));
model = glm::scale(model, transform->scale);
// Compute MVP
// Compute MVP matrix
glm::mat4 mvp = proj * view * model;
// Pass MVP to the shader
GLint mvpLoc = glGetUniformLocation(programID, "uMVP");
if(mvpLoc != -1)
{
glUniformMatrix4fv(mvpLoc, 1, GL_FALSE, glm::value_ptr(mvp));
}
else
{
DEBUG_PRINT("[RenderWindow] Warning: Uniform 'uMVP' not found in shader.");
}
// Pass MVP and Model matrices to the shader
m_ShaderPtr->SetMat4("uMVP", mvp);
m_ShaderPtr->SetMat4("uModel", model);
// Pass Model matrix to the shader
GLint modelLoc = glGetUniformLocation(programID, "uModel");
if(modelLoc != -1)
// Iterate through each submesh
for (const auto &submesh : mesh->submeshes)
{
glUniformMatrix4fv(modelLoc, 1, GL_FALSE, glm::value_ptr(model));
}
else
{
DEBUG_PRINT("[RenderWindow] Warning: Uniform 'uModel' not found in shader.");
}
// -----------------------------------
// 2) Bind the object's diffuse textures
// -----------------------------------
// Define the maximum number of diffuse textures as per the shader
const int MAX_DIFFUSE = 32; // Must match the shader's MAX_DIFFUSE
int textureUnit = 0;
// Iterate through all textures and bind those with type "texture_diffuse"
for (const auto &texture : mesh->textures)
{
if (texture.type == "texture_diffuse")
// Validate VAO
if (submesh.vao == 0)
{
if (textureUnit >= MAX_DIFFUSE)
{
DEBUG_PRINT("[RenderWindow] Warning: Exceeded maximum number of diffuse textures (%d) for shader.", MAX_DIFFUSE);
break; // Prevent exceeding the array bounds in the shader
}
// Activate the appropriate texture unit
glActiveTexture(GL_TEXTURE0 + textureUnit);
glBindTexture(GL_TEXTURE_2D, texture.id);
// Construct the uniform name dynamically (e.g., "uTextures.texture_diffuse[0]")
std::string uniformName = "uTextures.texture_diffuse[" + std::to_string(textureUnit) + "]";
GLint texLoc = glGetUniformLocation(programID, uniformName.c_str());
if (texLoc != -1)
{
glUniform1i(texLoc, textureUnit);
}
textureUnit++;
DEBUG_PRINT("[RenderWindow] Warning: Submesh VAO is not initialized.");
continue;
}
}
// Assign default texture to unused texture slots
for(int i = textureUnit; i < MAX_DIFFUSE; ++i)
{
std::string uniformName = "uTextures.texture_diffuse[" + std::to_string(i) + "]";
GLint texLoc = glGetUniformLocation(programID, uniformName.c_str());
if(texLoc != -1)
// Update triangle count
g_GPU_Triangles_drawn_to_screen += static_cast<int>(submesh.indices.size() / 3);
// Bind textures for the submesh
// Assuming the shader has uniform arrays like uTextures.texture_diffuse[32]
const int MAX_DIFFUSE = 32; // Must match the shader's MAX_DIFFUSE
int textureUnit = 0;
// Iterate through all textures and bind those with type "texture_diffuse"
for (const auto &texture : submesh.textures)
{
glUniform1i(texLoc, 0); // Assign texture unit 0 (ensure texture 0 is a valid default)
CheckOpenGLError("After glUniform1i for default texture");
if (texture.type == "texture_diffuse")
{
if (textureUnit >= MAX_DIFFUSE)
{
DEBUG_PRINT("[RenderWindow] Warning: Exceeded maximum number of diffuse textures (%d) for shader.", MAX_DIFFUSE);
break; // Prevent exceeding the array bounds in the shader
}
// Activate the appropriate texture unit
glActiveTexture(GL_TEXTURE0 + textureUnit);
glBindTexture(GL_TEXTURE_2D, texture.id);
// Construct the uniform name dynamically (e.g., "uTextures.texture_diffuse[0]")
std::string uniformName = "uTextures.texture_diffuse[" + std::to_string(textureUnit) + "]";
m_ShaderPtr->SetInt(uniformName, textureUnit);
textureUnit++;
}
}
}
// Set the number of active diffuse textures
GLint numDiffuseLoc = glGetUniformLocation(programID, "uNumDiffuseTextures");
if(numDiffuseLoc != -1)
{
glUniform1i(numDiffuseLoc, textureUnit);
CheckOpenGLError("After glUniform1i for uNumDiffuseTextures");
}
else
{
DEBUG_PRINT("[RenderWindow] Warning: Uniform 'uNumDiffuseTextures' not found in shader.");
}
// Assign default texture to unused texture slots to prevent shader errors
for(int i = textureUnit; i < MAX_DIFFUSE; ++i)
{
std::string uniformName = "uTextures.texture_diffuse[" + std::to_string(i) + "]";
m_ShaderPtr->SetInt(uniformName, 0); // Assign texture unit 0 (ensure texture 0 is a valid default)
}
// -----------------------------------
// 3) Draw the object's mesh
// -----------------------------------
glBindVertexArray(mesh->vao);
glDrawElements(GL_TRIANGLES, mesh->indexCount, GL_UNSIGNED_INT, nullptr);
glBindVertexArray(0);
CheckOpenGLError("After glDrawElements");
// Set the number of active diffuse textures
m_ShaderPtr->SetInt("uNumDiffuseTextures", textureUnit);
// Reset active texture
glActiveTexture(GL_TEXTURE0);
CheckOpenGLError("After glActiveTexture(GL_TEXTURE0)");
// Draw the submesh
glBindVertexArray(submesh.vao);
glDrawElements(GL_TRIANGLES, static_cast<GLsizei>(submesh.indices.size()), GL_UNSIGNED_INT, nullptr);
glBindVertexArray(0);
// Reset active texture to default
glActiveTexture(GL_TEXTURE0);
}
}
}
// Cleanup
// Cleanup: Unbind the shader program
glUseProgram(0);
CheckOpenGLError("After glUseProgram(0)");
// Unbind the FBO
m_FBO.Unbind();
CheckOpenGLError("After FBO Unbind");
}

View File

@ -22,14 +22,6 @@ std::shared_ptr<GameObject> CreateDefaultCube()
int newId = g_GameObjects.size();
auto newGameObject = std::make_shared<GameObject>(newId, ("New GameObject"));
newGameObject->AddComponent(std::make_shared<TransformComponent>()); // Ensure each entity has a TransformComponent by default
newGameObject->AddComponent(std::make_shared<MeshComponent>()); // Ensure each entity has a TransformComponent by default
// Suppose we loaded a VAO, an EBO with 36 indices for the cube,
// and a texture ID from the asset manager
std::shared_ptr<MeshComponent> mesh = newGameObject->GetComponent<MeshComponent>();
mesh->vao = CreateCubeVAO();
mesh->indexCount = 36;
return newGameObject;
}