Made it so the model load loads mtl files and textures, redid texture loading

This commit is contained in:
OusmBlueNinja 2024-12-29 22:25:16 -06:00
parent 8b44d35871
commit 17f847b561
79 changed files with 571309 additions and 637 deletions

Binary file not shown.

306
assets/models/sponza.mtl Normal file
View File

@ -0,0 +1,306 @@
# Blender MTL File: 'None'
# Material Count: 25
newmtl Material__25
Ns 7.843137
Ka 0.000000 0.000000 0.000000
Kd 0.470400 0.470400 0.470400
Ks 0.000000 0.000000 0.000000
Ni 1.000000
d 0.000000
illum 2
map_Kd textures/lion.tga
map_Disp textures/lion_ddn.tga
map_Ka textures/lion.tga
newmtl Material__298
Ns 7.843137
Ka 0.000000 0.000000 0.000000
Kd 0.470400 0.470400 0.470400
Ks 0.000000 0.000000 0.000000
Ni 1.000000
d 0.000000
illum 2
map_Kd textures/background.tga
map_Disp textures/background_ddn.tga
map_Ka textures/background.tga
newmtl Material__47
Ns 7.843137
Ka 0.000000 0.000000 0.000000
Kd 0.470400 0.470400 0.470400
Ks 0.000000 0.000000 0.000000
Ni 1.000000
d 0.000000
illum 2
newmtl Material__57
Ns 7.843137
Ka 0.000000 0.000000 0.000000
Kd 0.470400 0.470400 0.470400
Ks 0.000000 0.000000 0.000000
Ni 1.000000
d 1.000000
illum 2
map_Kd textures/vase_plant.tga
map_d textures/vase_plant_mask.tga
map_Ka textures/vase_plant.tga
newmtl arch
Ns 7.843137
Ka 0.000000 0.000000 0.000000
Kd 0.470400 0.470400 0.470400
Ks 0.000000 0.000000 0.000000
Ni 1.000000
d 0.000000
illum 2
map_Kd textures/sponza_arch_diff.tga
map_Ka textures/sponza_arch_diff.tga
map_Disp textures/sponza_arch_ddn.tga
newmtl bricks
Ns 7.843137
Ka 0.000000 0.000000 0.000000
Kd 0.470400 0.470400 0.470400
Ks 0.000000 0.000000 0.000000
Ni 1.000000
d 0.000000
illum 2
map_Kd textures/spnza_bricks_a_diff.tga
map_Disp textures/spnza_bricks_a_ddn.tga
map_Ka textures/spnza_bricks_a_diff.tga
newmtl ceiling
Ns 7.843137
Ka 0.000000 0.000000 0.000000
Kd 0.470400 0.470400 0.470400
Ks 0.000000 0.000000 0.000000
Ni 1.000000
d 0.000000
illum 2
map_Kd textures/sponza_ceiling_a_diff.tga
map_Ka textures/sponza_ceiling_a_diff.tga
map_Disp textures/sponza_ceiling_a_ddn.tga
newmtl chain
Ns 7.843137
Ka 0.000000 0.000000 0.000000
Kd 0.470400 0.470400 0.470400
Ks 0.000000 0.000000 0.000000
Ni 1.000000
d 1.000000
illum 2
map_Kd textures/chain_texture.tga
map_d textures/chain_texture_mask.tga
map_Disp textures/chain_texture_ddn.tga
map_Ka textures/chain_texture.tga
newmtl column_a
Ns 7.843137
Ka 0.000000 0.000000 0.000000
Kd 0.470400 0.470400 0.470400
Ks 0.000000 0.000000 0.000000
Ni 1.000000
d 0.000000
illum 2
map_Kd textures/sponza_column_a_diff.tga
map_Disp textures/sponza_column_a_ddn.tga
map_Ka textures/sponza_column_a_diff.tga
newmtl column_b
Ns 7.843137
Ka 0.000000 0.000000 0.000000
Kd 0.470400 0.470400 0.470400
Ks 0.000000 0.000000 0.000000
Ni 1.000000
d 0.000000
illum 2
map_Kd textures/sponza_column_b_diff.tga
map_Disp textures/sponza_column_b_ddn.tga
map_Ka textures/sponza_column_b_diff.tga
newmtl column_c
Ns 7.843137
Ka 0.000000 0.000000 0.000000
Kd 0.470400 0.470400 0.470400
Ks 0.000000 0.000000 0.000000
Ni 1.000000
d 0.000000
illum 2
map_Kd textures/sponza_column_c_diff.tga
map_Disp textures/sponza_column_c_ddn.tga
map_Ka textures/sponza_column_c_diff.tga
newmtl details
Ns 7.843137
Ka 0.000000 0.000000 0.000000
Kd 0.470400 0.470400 0.470400
Ks 0.000000 0.000000 0.000000
Ni 1.000000
d 0.000000
illum 2
map_Kd textures/sponza_details_diff.tga
map_Ka textures/sponza_details_diff.tga
map_Disp textures/sponza_details_ddn.tga
newmtl fabric_a
Ns 7.843137
Ka 0.000000 0.000000 0.000000
Kd 0.470400 0.470400 0.470400
Ks 0.000000 0.000000 0.000000
Ni 1.000000
d 0.000000
illum 2
map_Kd textures/sponza_fabric_diff.tga
map_Ka textures/sponza_fabric_diff.tga
map_Disp textures/sponza_fabric_ddn.tga
newmtl fabric_c
Ns 7.843137
Ka 0.000000 0.000000 0.000000
Kd 0.470400 0.470400 0.470400
Ks 0.000000 0.000000 0.000000
Ni 1.000000
d 0.000000
illum 2
map_Kd textures/sponza_curtain_diff.tga
map_Ka textures/sponza_curtain_diff.tga
map_Disp textures/sponza_curtain_ddn.tga
newmtl fabric_d
Ns 7.843137
Ka 0.000000 0.000000 0.000000
Kd 0.470400 0.470400 0.470400
Ks 0.000000 0.000000 0.000000
Ni 1.000000
d 0.000000
illum 2
map_Kd textures/sponza_fabric_blue_diff.tga
map_Ka textures/sponza_fabric_blue_diff.tga
map_Disp textures/sponza_fabric_ddn.tga
newmtl fabric_e
Ns 7.843137
Ka 0.000000 0.000000 0.000000
Kd 0.470400 0.470400 0.470400
Ks 0.000000 0.000000 0.000000
Ni 1.000000
d 0.000000
illum 2
map_Kd textures/sponza_fabric_green_diff.tga
map_Ka textures/sponza_fabric_green_diff.tga
map_Disp textures/sponza_fabric_ddn.tga
newmtl fabric_f
Ns 7.843137
Ka 0.000000 0.000000 0.000000
Kd 0.470400 0.470400 0.470400
Ks 0.000000 0.000000 0.000000
Ni 1.000000
d 0.000000
illum 2
map_Kd textures/sponza_curtain_green_diff.tga
map_Ka textures/sponza_curtain_green_diff.tga
map_Disp textures/sponza_curtain_ddn.tga
newmtl fabric_g
Ns 7.843137
Ka 0.000000 0.000000 0.000000
Kd 0.470400 0.470400 0.470400
Ks 0.000000 0.000000 0.000000
Ni 1.000000
d 0.000000
illum 2
map_Kd textures/sponza_curtain_blue_diff.tga
map_Ka textures/sponza_curtain_blue_diff.tga
map_Disp textures/sponza_curtain_ddn.tga
newmtl flagpole
Ns 7.843137
Ka 0.000000 0.000000 0.000000
Kd 0.470400 0.470400 0.470400
Ks 0.000000 0.000000 0.000000
Ni 1.000000
d 0.000000
illum 2
map_Kd textures/sponza_flagpole_diff.tga
map_Ka textures/sponza_flagpole_diff.tga
map_Disp textures/sponza_flagpole_ddn.tga
newmtl floor
Ns 7.843137
Ka 0.000000 0.000000 0.000000
Kd 0.470400 0.470400 0.470400
Ks 0.000000 0.000000 0.000000
Ni 1.000000
d 0.000000
illum 2
map_Kd textures/sponza_floor_a_diff.tga
map_Ka textures/sponza_floor_a_diff.tga
map_Disp textures/sponza_floor_a_ddn.tga
newmtl leaf
Ns 7.843137
Ka 0.000000 0.000000 0.000000
Kd 0.470400 0.470400 0.470400
Ks 0.000000 0.000000 0.000000
Ni 1.000000
d 1.000000
illum 2
map_Kd textures/sponza_thorn_diff.tga
map_d textures/sponza_thorn_mask.tga
map_Disp textures/sponza_thorn_ddn.tga
map_Ka textures/sponza_thorn_diff.tga
newmtl roof
Ns 7.843137
Ka 0.000000 0.000000 0.000000
Kd 0.470400 0.470400 0.470400
Ks 0.000000 0.000000 0.000000
Ni 1.000000
d 0.000000
illum 2
map_Kd textures/sponza_roof_diff.tga
map_Ka textures/sponza_roof_diff.tga
map_Disp textures/sponza_roof_ddn.tga
newmtl vase
Ns 7.843137
Ka 0.000000 0.000000 0.000000
Kd 0.470400 0.470400 0.470400
Ks 0.000000 0.000000 0.000000
Ni 1.000000
d 0.000000
illum 2
map_Kd textures/vase_dif.tga
map_Ka textures/vase_dif.tga
map_Disp textures/vase_ddn.tga
newmtl vase_hanging
Ns 7.843137
Ka 0.000000 0.000000 0.000000
Kd 0.470400 0.470400 0.470400
Ks 0.000000 0.000000 0.000000
Ni 1.000000
d 0.000000
illum 2
map_Kd textures/vase_hanging.tga
map_Ka textures/vase_hanging.tga
map_Disp textures/vase_hanging_ddn.tga
newmtl vase_round
Ns 7.843137
Ka 0.000000 0.000000 0.000000
Kd 0.470400 0.470400 0.470400
Ks 0.000000 0.000000 0.000000
Ni 1.000000
d 0.000000
illum 2
map_Kd textures/vase_round.tga
map_Disp textures/vase_round_ddn.tga
map_Ka textures/vase_round.tga

569548
assets/models/sponza.obj Normal file

File diff suppressed because it is too large Load Diff

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 768 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.0 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.0 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.0 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 192 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.0 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 MiB

View File

@ -66,7 +66,7 @@ function OnUpdate(deltaTime)
-- Define the new rotation (spinning around the Y-axis)
local rotation = {
x = -180, -- Preserving existing rotation on X-axis
x = 0, -- Preserving existing rotation on X-axis
y = new_rotation, -- Updated rotation on Y-axis for spinning
z = 0 -- Preserving existing rotation on Z-axis
}

View File

@ -1 +1 @@
return _T_Engine_Table
return _T_Engine_Table -- This just returns the Global Table that the engine creates

View File

@ -0,0 +1,36 @@
#version 330
struct Textures {
sampler2D texture_diffuse;
sampler2D texture_specular;
sampler2D texture_normal;
// Add more as needed
};
uniform Textures uTextures;
in vec2 TexCoord;
in vec3 Normal;
in vec3 FragPos;
out vec4 FragColor;
void main()
{
// Example: Combine diffuse and specular textures
vec4 diffuseColor = texture(uTextures.texture_diffuse, TexCoord);
vec4 specularColor = texture(uTextures.texture_specular, TexCoord);
// Simple lighting calculation (for demonstration)
vec3 lightDir = normalize(vec3(0.5, 1.0, 0.3));
float diff = max(dot(Normal, lightDir), 0.0);
vec3 diffuse = diff * diffuseColor.rgb;
vec3 viewDir = normalize(-FragPos); // Assuming camera at origin
vec3 reflectDir = reflect(-lightDir, Normal);
float spec = pow(max(dot(viewDir, reflectDir), 0.0), 32);
vec3 specular = spec * specularColor.rgb;
vec3 result = diffuse + specular;
FragColor = vec4(result, diffuseColor.a);
}

View File

@ -0,0 +1,19 @@
#version 330
layout(location = 0) in vec3 aPos;
layout(location = 1) in vec2 aTexCoord;
layout(location = 2) in vec3 aNormal;
uniform mat4 uMVP;
out vec2 TexCoord;
out vec3 Normal;
out vec3 FragPos;
void main()
{
gl_Position = uMVP * vec4(aPos, 1.0);
TexCoord = aTexCoord;
Normal = aNormal;
FragPos = vec3(uMVP * vec4(aPos, 1.0));
}

View File

@ -1,18 +1,48 @@
#version 330 core
in vec2 vUV; // UV from vertex shader
out vec4 FragColor; // Final color output
// Struct to hold an array of diffuse textures
struct TextureArray {
sampler2D texture_diffuse[32]; // Array of diffuse texture samplers
};
uniform vec4 uColor; // A user-set solid color
uniform sampler2D uTexture; // Optional texture
// Uniforms
uniform TextureArray uTextures; // Array of diffuse textures
uniform int uNumDiffuseTextures; // Number of active diffuse textures
// Input variables from the vertex shader
in vec2 TexCoords; // Texture coordinates
// Output fragment color
out vec4 FragColor;
void main()
{
// Sample the texture. If you don't want texturing, remove this.
vec4 texColor = texture(uTexture, vUV);
// Define grid dimensions
const int gridCols = 8; // Number of columns in the grid
const int gridRows = 4; // Number of rows in the grid
const float gridWidth = 1.0 / float(gridCols);
const float gridHeight = 1.0 / float(gridRows);
// Multiply the texture by our uniform color.
// If you want a pure color (no texture), just do:
// FragColor = uColor;
FragColor = texColor * texColor;
// Calculate grid cell indices based on TexCoords
int col = int(floor(TexCoords.x / gridWidth));
int row = int(floor(TexCoords.y / gridHeight));
// Clamp indices to grid boundaries to prevent out-of-range access
col = clamp(col, 0, gridCols - 1);
row = clamp(row, 0, gridRows - 1);
// Calculate texture index based on row and column
int texIndex = row * gridCols + col;
// Clamp texture index to the number of active textures
texIndex = clamp(texIndex, 0, uNumDiffuseTextures - 1);
// Calculate local texture coordinates within the grid cell
vec2 localTexCoords = fract(TexCoords / vec2(gridWidth, gridHeight));
// Sample the selected texture using localTexCoords
vec4 color = texture(uTextures.texture_diffuse[texIndex], localTexCoords);
// Set the final fragment color
FragColor = color;
}

View File

@ -1,14 +1,30 @@
#version 330 core
layout(location = 0) in vec3 aPos; // Vertex position
layout(location = 1) in vec2 aUV; // Texture UV coordinate (optional)
// 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
uniform mat4 uMVP; // Combined Model-View-Projection matrix
// Uniforms
uniform mat4 uMVP; // Model-View-Projection matrix
uniform mat4 uModel; // Model matrix
out vec2 vUV; // Pass UV to the fragment shader
// Output variables to the fragment shader
out vec2 TexCoords; // Passed texture coordinates
out vec3 Normal; // Passed normal vector
out vec3 FragPos; // Passed fragment position
void main()
{
vUV = aUV;
// Calculate the position of the vertex in clip space
gl_Position = uMVP * vec4(aPos, 1.0);
// Calculate the position of the vertex in world space
FragPos = vec3(uModel * vec4(aPos, 1.0));
// Calculate the normal vector in world space
Normal = mat3(transpose(inverse(uModel))) * aNormal;
// Pass through the texture coordinates
TexCoords = aTexCoords;
}

View File

@ -67,32 +67,32 @@ Size=1920,1177
Collapsed=0
[Window][Inspector##InspectorWindow]
Pos=1567,27
Size=345,1142
Pos=1536,27
Size=376,1142
Collapsed=0
DockId=0x00000016,0
[Window][Editor##EditorWindow]
Pos=275,27
Size=1290,660
Pos=274,27
Size=1260,751
Collapsed=0
DockId=0x00000017,0
[Window][Performance##performance]
Pos=8,720
Size=265,449
Pos=8,594
Size=264,575
Collapsed=0
DockId=0x00000014,0
DockId=0x0000001A,0
[Window][Logger##logger]
Pos=275,689
Size=797,480
Pos=274,780
Size=612,389
Collapsed=0
DockId=0x0000001B,0
[Window][Lua Text Editor##LuaEditor]
Pos=1074,689
Size=491,480
Pos=888,780
Size=646,389
Collapsed=0
DockId=0x0000001C,0
@ -104,19 +104,19 @@ DockId=0x0000000F,0
[Window][Scene Window##SceneWindow]
Pos=8,27
Size=265,691
Size=264,565
Collapsed=0
DockId=0x00000013,0
DockId=0x00000019,0
[Window][Game Objects]
Pos=182,27
Size=301,571
Collapsed=0
DockId=0x0000001A,0
DockId=0x00000011,0
[Window][Profiler]
Pos=932,689
Size=633,480
Pos=889,689
Size=676,480
Collapsed=0
DockId=0x0000001C,1
@ -127,34 +127,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=0x00000015 Parent=0x14621557 SizeRef=1557,1142 Split=X
DockNode ID=0x00000011 Parent=0x00000015 SizeRef=265,1142 Split=X Selected=0x1D5D92B6
DockNode ID=0x00000019 Parent=0x00000011 SizeRef=172,571 Split=Y Selected=0x1D5D92B6
DockNode ID=0x00000013 Parent=0x00000019 SizeRef=326,691 HiddenTabBar=1 Selected=0x1D5D92B6
DockNode ID=0x00000014 Parent=0x00000019 SizeRef=326,449 HiddenTabBar=1 Selected=0x818D04BB
DockNode ID=0x0000001A Parent=0x00000011 SizeRef=301,571 Selected=0xD71D2CC1
DockNode ID=0x00000012 Parent=0x00000015 SizeRef=1290,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,660 CentralNode=1 HiddenTabBar=1 Selected=0xDFF75B3F
DockNode ID=0x00000018 Parent=0x0000000D SizeRef=1303,480 Split=X Selected=0x9B5D3198
DockNode ID=0x0000001B Parent=0x00000018 SizeRef=797,680 HiddenTabBar=1 Selected=0x1C0788A1
DockNode ID=0x0000001C Parent=0x00000018 SizeRef=491,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=0x14621557 SizeRef=345,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,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

87
scenes/Cool_Model.scene Normal file
View File

@ -0,0 +1,87 @@
Entities:
- ID: 1
Name: Gun
Components:
ScriptComponent:
ScriptPath: assets/scripts/BouncingItem.lua
Transform:
Position: [0, 1.79999995, 0]
Rotation: [0, 71.8000031, 0]
Scale: [0.00999999978, 0.00999999978, 0.00999999978]
Mesh:
vao: 4
indexCount: 786801
textures:
- id: 11
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
MeshPath: assets/models/sponza.obj

View File

@ -2,113 +2,113 @@ Entities:
- ID: 0
Name: Player
Components:
Transform:
Position: [0, 2.79999995, -12.6000004]
Rotation: [498.009338, 498.009338, 498.009338]
Scale: [1, 1, 1]
Mesh:
vao: 2
indexCount: 15810
textureID: 1
MeshPath: assets/models/LowPolyFiatUNO.obj
Transform:
Position: [0, 2.79999995, -12.6000004]
Rotation: [185.076614, 185.076614, 185.076614]
Scale: [1, 1, 1]
- ID: 2
Name: Gun
Components:
ScriptComponent:
ScriptPath: assets/scripts/BouncingItem.lua
Transform:
Position: [-2.5, 0.755197883, -0.300000012]
Rotation: [-180, 105.403984, 0]
Scale: [0.00499999989, 0.00499999989, 0.00499999989]
Mesh:
vao: 5
indexCount: 116445
textureID: 5
MeshPath: assets/models/Ak-47.obj
Transform:
Position: [-2.5, 0.806414127, -0.300000012]
Rotation: [-180, 261.233307, 0]
Scale: [0.00499999989, 0.00499999989, 0.00499999989]
ScriptComponent:
ScriptPath: assets/scripts/BouncingItem.lua
- ID: 3
Name: Grass Box Top
Components:
Transform:
Position: [-1.20000005, -3.4000001, -17.7000008]
Rotation: [-23.5, 15.8999996, -59.9000015]
Scale: [1, 1, 1]
Mesh:
vao: 1
indexCount: 36
textureID: 4
MeshPath: assets/models/DefaultMesh.obj
Transform:
Position: [-1.20000005, -3.4000001, -17.7000008]
Rotation: [-23.5, 15.8999996, -59.9000015]
Scale: [1, 1, 1]
- ID: 4
Name: Bark Box
Components:
Transform:
Position: [8.10000038, 0.800000012, -12]
Rotation: [-17.2999992, -16.1000004, -19.2999992]
Scale: [1, 1, 1]
Mesh:
vao: 1
indexCount: 36
textureID: 5
MeshPath: assets/models/DefaultMesh.obj
Transform:
Position: [8.10000038, 0.800000012, -12]
Rotation: [-17.2999992, -16.1000004, -19.2999992]
Scale: [1, 1, 1]
- ID: 5
Name: Skybox
Components:
Transform:
Position: [0, 0, 43.2000008]
Rotation: [0, 0, 0]
Scale: [100, 100, 100]
Mesh:
vao: 1
indexCount: 36
textureID: 7
MeshPath: assets/models/DefaultMesh.obj
Transform:
Position: [0, 0, 43.2000008]
Rotation: [0, 0, 0]
Scale: [100, 100, 100]
- ID: 6
Name: Null Texture Box
Components:
Transform:
Position: [-6.5, -6, -18]
Rotation: [15.8000002, -18.2000008, -11.1000004]
Scale: [1, 1, 1]
Mesh:
vao: 1
indexCount: 36
textureID: 3
MeshPath: assets/models/DefaultMesh.obj
Transform:
Position: [-6.5, -6, -18]
Rotation: [15.8000002, -18.2000008, -11.1000004]
Scale: [1, 1, 1]
- ID: 7
Name: Grass Box Bottom
Components:
Transform:
Position: [6.5999999, 1.79999995, -23.8999996]
Rotation: [-16.1000004, -15.8999996, -35]
Scale: [1, 1, 1]
Mesh:
vao: 1
indexCount: 36
textureID: 4
MeshPath: assets/models/DefaultMesh.obj
Transform:
Position: [6.5999999, 1.79999995, -23.8999996]
Rotation: [-16.1000004, -15.8999996, -35]
Scale: [1, 1, 1]
- ID: 8
Name: Wood Box
Components:
Transform:
Position: [-7.80000019, 0.200000003, -29.7999992]
Rotation: [22.2999992, -32.7999992, 0]
Scale: [1, 1, 1]
Mesh:
vao: 1
indexCount: 36
textureID: 1
MeshPath: assets/models/DefaultMesh.obj
Transform:
Position: [-7.80000019, 0.200000003, -29.7999992]
Rotation: [22.2999992, -32.7999992, 0]
Scale: [1, 1, 1]
- ID: 9
Name: Bricks
Components:
Transform:
Position: [5.5, -2.9000001, -19.5]
Rotation: [-41.4000015, -22.6000004, -52.2999992]
Scale: [1, 1, 1]
Mesh:
vao: 1
indexCount: 36
textureID: 2
MeshPath: assets/models/DefaultMesh.obj
Transform:
Position: [5.5, -2.9000001, -19.5]
Rotation: [-41.4000015, -22.6000004, -52.2999992]
Scale: [1, 1, 1]
- ID: 10
Name: Script
Components:
@ -117,12 +117,31 @@ Entities:
- ID: 10
Name: Gun Podium
Components:
Transform:
Position: [-2.5, 2, -0.300000012]
Rotation: [0, 0, 0]
Scale: [0.25, 1, 0.25]
Mesh:
vao: 1
indexCount: 36
textureID: 4
MeshPath: assets/models/DefaultMesh.obj
Transform:
Position: [-2.5, 2, -0.300000012]
Rotation: [0, 0, 0]
Scale: [0.25, 1, 0.25]
- ID: 11
Name: Camera
Components:
CameraComponent:
IsPerspective: true
DefaultRuntimeCamera: true
FOV: 45
AspectRatio: 1.77777779
NearPlane: 0.100000001
FarPlane: 1000
Mesh:
vao: 0
indexCount: 36
textureID: 0
MeshPath: assets/models/DefaultMesh.obj
Transform:
Position: [0, -0.100000001, 0.400000006]
Rotation: [15.3999996, -164.399994, 0]
Scale: [1, 1, 1]

View File

@ -1,121 +1,147 @@
Entities:
- ID: 0
Name: Carrrrr Yeaaa
Name: Player
Components:
Transform:
Position: [0, 2.79999995, -12.6000004]
Rotation: [149.699997, -137.899994, -39.2999992]
Rotation: [498.009338, 498.009338, 498.009338]
Scale: [1, 1, 1]
Mesh:
vao: 2
indexCount: 15810
textureID: 1
MeshPath: assets/models/LowPolyFiatUNO.obj
- ID: 1
Name: Cube Yay
Components:
Transform:
Position: [-11.8999996, -2, -21.7999992]
Rotation: [-9, -18.6000004, -28.1000004]
Scale: [1, 1, 1]
Mesh:
vao: 5
indexCount: 36
textureID: 2
MeshPath: assets/models/DefaultMesh.obj
- ID: 2
Name: Cube Yay 2
Name: Gun
Components:
Transform:
Position: [7.80000019, -8.10000038, -20.6000004]
Rotation: [-86.3000031, 0, -66]
Scale: [1, 1, 1]
Position: [-2.5, 0.755197883, -0.300000012]
Rotation: [-180, 105.403984, 0]
Scale: [0.00499999989, 0.00499999989, 0.00499999989]
Mesh:
vao: 5
indexCount: 36
textureID: 3
MeshPath: assets/models/DefaultMesh.obj
indexCount: 116445
textureID: 5
MeshPath: assets/models/Ak-47.obj
ScriptComponent:
ScriptPath: assets/scripts/BouncingItem.lua
- ID: 3
Name: Cube Yay 3
Name: Grass Box Top
Components:
Transform:
Position: [-1.20000005, -3.4000001, -17.7000008]
Rotation: [-23.5, 15.8999996, -59.9000015]
Scale: [1, 1, 1]
Mesh:
vao: 5
vao: 1
indexCount: 36
textureID: 4
MeshPath: assets/models/DefaultMesh.obj
- ID: 4
Name: Cube Yay 4
Name: Bark Box
Components:
Transform:
Position: [8.10000038, 0.800000012, -12]
Rotation: [-17.2999992, -16.1000004, -19.2999992]
Scale: [1, 1, 1]
Mesh:
vao: 5
vao: 1
indexCount: 36
textureID: 5
MeshPath: assets/models/DefaultMesh.obj
- ID: 5
Name: Colormap
Name: Skybox
Components:
Mesh:
vao: 5
vao: 1
indexCount: 36
textureID: 6
textureID: 7
MeshPath: assets/models/DefaultMesh.obj
Transform:
Position: [0, 0, 0]
Rotation: [0, 0, -90]
Position: [0, 0, 43.2000008]
Rotation: [0, 0, 0]
Scale: [100, 100, 100]
- ID: 6
Name: Cube Yay 6
Name: Null Texture Box
Components:
Transform:
Position: [-6.5, -6, -18]
Rotation: [15.8000002, -18.2000008, -11.1000004]
Scale: [1, 1, 1]
Mesh:
vao: 5
vao: 1
indexCount: 36
textureID: 3
MeshPath: assets/models/DefaultMesh.obj
- ID: 7
Name: Cube Yay 7
Name: Grass Box Bottom
Components:
Transform:
Position: [6.5, 1.79999995, -23.8999996]
Position: [6.5999999, 1.79999995, -23.8999996]
Rotation: [-16.1000004, -15.8999996, -35]
Scale: [1, 1, 1]
Mesh:
vao: 5
vao: 1
indexCount: 36
textureID: 4
MeshPath: assets/models/DefaultMesh.obj
- ID: 8
Name: Cube Yay 8
Name: Wood Box
Components:
Transform:
Position: [-7.80000019, 0.200000003, -29.7999992]
Rotation: [22.2999992, -32.7999992, 0]
Scale: [1, 1, 1]
Mesh:
vao: 5
vao: 1
indexCount: 36
textureID: 1
MeshPath: assets/models/DefaultMesh.obj
- ID: 9
Name: Cube Yay 9
Name: Bricks
Components:
Transform:
Position: [5.5, -2.9000001, -19.5]
Rotation: [-41.4000015, -22.6000004, -52.2999992]
Scale: [1, 1, 1]
Mesh:
vao: 5
vao: 1
indexCount: 36
textureID: 2
MeshPath: assets/models/DefaultMesh.obj
- ID: 10
Name: Script
Components:
ScriptComponent:
ScriptPath: assets/scripts/script.lua
- ID: 10
Name: Gun Podium
Components:
Mesh:
vao: 1
indexCount: 36
textureID: 4
MeshPath: assets/models/DefaultMesh.obj
Transform:
Position: [-2.5, 2, -0.300000012]
Rotation: [0, 0, 0]
Scale: [0.25, 1, 0.25]
- ID: 11
Name: Camera
Components:
CameraComponent:
IsPerspective: true
DefaultRuntimeCamera: true
FOV: 45
AspectRatio: 1.77777779
NearPlane: 0.100000001
FarPlane: 1000
Mesh:
vao: 0
indexCount: 36
textureID: 0
MeshPath: assets/models/DefaultMesh.obj
Transform:
Position: [0, -0.100000001, 0.400000006]
Rotation: [15.3999996, -164.399994, 0]
Scale: [1, 1, 1]

View File

@ -4,14 +4,16 @@
#include "GameObject.h" // Ensure this is included to access GameObject
#include "Transform.h" // Ensure Transform component is available
#include <iostream>
#include <cassert>
#include "gcml.h"
// Constructor implementation
CameraComponent::CameraComponent() :
m_IsPerspective(true),
m_FOV(45.0f), m_AspectRatio(16.0f / 9.0f),
m_NearPlane(0.1f), m_FarPlane(100.0f),
m_Left(-1.0f), m_Right(1.0f), m_Bottom(-1.0f), m_Top(1.0f),
m_ViewMatrix(1.0f), m_ProjectionMatrix(1.0f)
CameraComponent::CameraComponent() : IsPerspective(true),
FOV(45.0f), AspectRatio(16.0f / 9.0f),
NearPlane(0.1f), FarPlane(100.0f),
Left(-1.0f), Right(1.0f), Bottom(-1.0f), Top(1.0f), DefaultRuntimeCamera(false),
m_ViewMatrix(1.0f), m_ProjectionMatrix(1.0f)
{
UpdateProjectionMatrix();
}
@ -33,27 +35,27 @@ const std::string &CameraComponent::GetStaticName()
return name;
}
YAML::Node CameraComponent::Serialize()
{
YAML::Node node;
node["IsPerspective"] = m_IsPerspective;
if (m_IsPerspective)
node["IsPerspective"] = IsPerspective;
node["DefaultRuntimeCamera"] = DefaultRuntimeCamera;
if (IsPerspective)
{
node["FOV"] = m_FOV;
node["AspectRatio"] = m_AspectRatio;
node["NearPlane"] = m_NearPlane;
node["FarPlane"] = m_FarPlane;
node["FOV"] = FOV;
node["AspectRatio"] = AspectRatio;
node["NearPlane"] = NearPlane;
node["FarPlane"] = FarPlane;
}
else
{
node["Left"] = m_Left;
node["Right"] = m_Right;
node["Bottom"] = m_Bottom;
node["Top"] = m_Top;
node["NearPlane"] = m_NearPlane;
node["FarPlane"] = m_FarPlane;
node["Left"] = Left;
node["Right"] = Right;
node["Bottom"] = Bottom;
node["Top"] = Top;
node["NearPlane"] = NearPlane;
node["FarPlane"] = FarPlane;
}
return node;
}
@ -62,59 +64,63 @@ void CameraComponent::Deserialize(const YAML::Node &node)
{
if (node["IsPerspective"])
{
m_IsPerspective = node["IsPerspective"].as<bool>();
IsPerspective = node["IsPerspective"].as<bool>();
}
if (m_IsPerspective)
if (node["DefaultRuntimeCamera"])
{
DefaultRuntimeCamera = node["DefaultRuntimeCamera"].as<bool>();
}
if (IsPerspective)
{
if (node["FOV"])
m_FOV = node["FOV"].as<float>();
FOV = node["FOV"].as<float>();
if (node["AspectRatio"])
m_AspectRatio = node["AspectRatio"].as<float>();
AspectRatio = node["AspectRatio"].as<float>();
if (node["NearPlane"])
m_NearPlane = node["NearPlane"].as<float>();
NearPlane = node["NearPlane"].as<float>();
if (node["FarPlane"])
m_FarPlane = node["FarPlane"].as<float>();
FarPlane = node["FarPlane"].as<float>();
}
else
{
if (node["Left"])
m_Left = node["Left"].as<float>();
Left = node["Left"].as<float>();
if (node["Right"])
m_Right = node["Right"].as<float>();
Right = node["Right"].as<float>();
if (node["Bottom"])
m_Bottom = node["Bottom"].as<float>();
Bottom = node["Bottom"].as<float>();
if (node["Top"])
m_Top = node["Top"].as<float>();
Top = node["Top"].as<float>();
if (node["NearPlane"])
m_NearPlane = node["NearPlane"].as<float>();
NearPlane = node["NearPlane"].as<float>();
if (node["FarPlane"])
m_FarPlane = node["FarPlane"].as<float>();
FarPlane = node["FarPlane"].as<float>();
}
UpdateProjectionMatrix();
UpdateViewMatrix();
}
void CameraComponent::SetPerspective(float fov, float aspectRatio, float nearPlane, float farPlane)
{
m_IsPerspective = true;
m_FOV = fov;
m_AspectRatio = aspectRatio;
m_NearPlane = nearPlane;
m_FarPlane = farPlane;
IsPerspective = true;
FOV = fov;
AspectRatio = aspectRatio;
NearPlane = nearPlane;
FarPlane = farPlane;
UpdateProjectionMatrix();
}
void CameraComponent::SetOrthographic(float left, float right, float bottom, float top, float nearPlane, float farPlane)
{
m_IsPerspective = false;
m_Left = left;
m_Right = right;
m_Bottom = bottom;
m_Top = top;
m_NearPlane = nearPlane;
m_FarPlane = farPlane;
IsPerspective = false;
Left = left;
Right = right;
Bottom = bottom;
Top = top;
NearPlane = nearPlane;
FarPlane = farPlane;
UpdateProjectionMatrix();
}
@ -128,45 +134,60 @@ const glm::mat4 &CameraComponent::GetProjectionMatrix() const
return m_ProjectionMatrix;
}
void CameraComponent::Update(float _deltaTime)
{
(void)_deltaTime; // Suppress unused parameter warning
UpdateViewMatrix();
UpdateProjectionMatrix();
}
void CameraComponent::UpdateViewMatrix()
{
// Retrieve the Transform component from the owning GameObject
std::shared_ptr<TransformComponent> transform = owner->GetComponent<TransformComponent>();
if (transform)
if (m_Owner)
{
glm::vec3 position = transform->GetPosition();
glm::vec3 rotation = transform->GetRotation();
// Convert Euler angles to radians
glm::vec3 rotRad = glm::radians(rotation);
std::shared_ptr<TransformComponent> transform = m_Owner->GetComponent<TransformComponent>();
// Calculate forward vector
glm::vec3 forward;
forward.x = cos(rotRad.y) * cos(rotRad.x);
forward.y = sin(rotRad.x);
forward.z = sin(rotRad.y) * cos(rotRad.x);
forward = glm::normalize(forward);
if (transform)
{
glm::vec3 position = transform->GetPosition();
glm::vec3 rotation = transform->GetRotation();
// Define up vector (assuming Y-up)
glm::vec3 up = glm::vec3(0.0f, 1.0f, 0.0f);
// Convert Euler angles to radians
glm::vec3 rotRad = glm::radians(rotation);
m_ViewMatrix = glm::lookAt(position, position + forward, up);
// Calculate forward vector
glm::vec3 forward;
forward.x = cos(rotRad.y) * cos(rotRad.x);
forward.y = sin(rotRad.x);
forward.z = sin(rotRad.y) * cos(rotRad.x);
forward = glm::normalize(forward);
// Define up vector (assuming Y-up)
glm::vec3 up = glm::vec3(0.0f, 1.0f, 0.0f);
m_ViewMatrix = glm::lookAt(position, position + forward, up);
}
else
{
DEBUG_PRINT("Transform component missing on GameObject: %s", m_Owner->name.c_str());
}
}
else
{
std::cerr << "Transform component missing on GameObject: " << m_Owner->name << std::endl;
DEBUG_PRINT("Game Object has no parent");
}
}
void CameraComponent::UpdateProjectionMatrix()
{
if (m_IsPerspective)
if (IsPerspective)
{
m_ProjectionMatrix = glm::perspective(glm::radians(m_FOV), m_AspectRatio, m_NearPlane, m_FarPlane);
m_ProjectionMatrix = glm::perspective(glm::radians(FOV), AspectRatio, NearPlane, FarPlane);
}
else
{
m_ProjectionMatrix = glm::ortho(m_Left, m_Right, m_Bottom, m_Top, m_NearPlane, m_FarPlane);
m_ProjectionMatrix = glm::ortho(Left, Right, Bottom, Top, NearPlane, FarPlane);
}
}

View File

@ -16,40 +16,40 @@ public:
virtual ~CameraComponent();
// Overridden methods from Component
virtual const std::string& GetName() const override;
virtual const std::string &GetName() const override;
static const std::string& GetStaticName();
static const std::string &GetStaticName();
virtual YAML::Node Serialize() override;
virtual void Deserialize(const YAML::Node& node) override;
virtual void Deserialize(const YAML::Node &node) override;
// Camera-specific methods
void SetPerspective(float fov, float aspectRatio, float nearPlane, float farPlane);
void SetOrthographic(float left, float right, float bottom, float top, float nearPlane, float farPlane);
const glm::mat4& GetViewMatrix() const;
const glm::mat4& GetProjectionMatrix() const;
const glm::mat4 &GetViewMatrix() const;
const glm::mat4 &GetProjectionMatrix() const;
// Projection parameters
bool IsPerspective;
float FOV;
float AspectRatio;
float NearPlane;
float FarPlane;
float Left;
float Right;
float Bottom;
float Top;
bool DefaultRuntimeCamera;
virtual void Update(float deltaTime) override;
private:
// Projection parameters
bool m_IsPerspective;
float m_FOV;
float m_AspectRatio;
float m_NearPlane;
float m_FarPlane;
float m_Left;
float m_Right;
float m_Bottom;
float m_Top;
// Matrices
glm::mat4 m_ViewMatrix;
glm::mat4 m_ProjectionMatrix;
GameObject* owner;
// Update matrices
void UpdateViewMatrix();
void UpdateProjectionMatrix();

View File

@ -18,21 +18,23 @@ public:
virtual ~Component() {}
// Pure virtual methods
virtual const std::string& GetName() const = 0;
virtual const std::string &GetName() const = 0;
void SetOwner(GameObject* owner) {
void SetOwner(GameObject *owner)
{
m_Owner = owner;
}
virtual void Update(float deltaTime) = 0;
// Serialization methods
virtual YAML::Node Serialize() = 0;
virtual void Deserialize(const YAML::Node& node) = 0;
virtual void Deserialize(const YAML::Node &node) = 0;
// Getter for the owning GameObject
GameObject* GetOwner() const { return m_Owner; }
GameObject *GetOwner() const { return m_Owner; }
protected:
GameObject* m_Owner; // Pointer to the owning GameObject
GameObject *m_Owner; // Pointer to the owning GameObject
};

View File

@ -32,6 +32,19 @@ void GameObject::AddComponent(const std::shared_ptr<Component> &component)
// std::cout << "Added " << component->GetName() << std::endl;
}
void GameObject::Update(float deltaTime) {
// Iterate using range-based for loop
for (const auto& [componentName, componentPtr] : components) {
if (componentPtr) { // Check if the pointer is valid
componentPtr->Update(deltaTime); // Call the Update method
} else {
DEBUG_PRINT("Warning: '%s' is not a valid pointer:", componentName.c_str());
}
}
}
std::shared_ptr<Component> GameObject::GetComponentByName(const std::string &name) const
{
auto it = components.find(name);
@ -83,21 +96,27 @@ void GameObject::Deserialize(const YAML::Node &node)
if (compName == TransformComponent::GetStaticName())
{
auto transform = std::make_shared<TransformComponent>();
transform->Deserialize(compNode);
AddComponent(transform);
auto NewComponent = std::make_shared<TransformComponent>();
NewComponent->Deserialize(compNode);
AddComponent(NewComponent);
}
else if (compName == MeshComponent::GetStaticName())
{
auto mesh = std::make_shared<MeshComponent>();
mesh->Deserialize(compNode);
AddComponent(mesh);
auto NewComponent = std::make_shared<MeshComponent>();
NewComponent->Deserialize(compNode);
AddComponent(NewComponent);
}
else if (compName == ScriptComponent::GetStaticName())
{
auto ScriptComp = std::make_shared<ScriptComponent>();
ScriptComp->Deserialize(compNode);
AddComponent(ScriptComp);
auto NewComponent = std::make_shared<ScriptComponent>();
NewComponent->Deserialize(compNode);
AddComponent(NewComponent);
}
else if (compName == CameraComponent::GetStaticName())
{
auto NewComponent = std::make_shared<CameraComponent>();
NewComponent->Deserialize(compNode);
AddComponent(NewComponent);
}
else
{

View File

@ -9,6 +9,7 @@
#include "Transform.h"
#include "ScriptComponent.h"
#include "Mesh.h"
#include "CameraComponent.h"
#include <yaml-cpp/yaml.h>
@ -30,6 +31,8 @@ public:
void AddComponent(const std::shared_ptr<Component> &component);
std::shared_ptr<Component> GetComponentByName(const std::string &name) const;
void Update(float deltaTime);
template <typename T>
std::shared_ptr<T> GetComponent()
{

View File

@ -10,7 +10,7 @@ extern AssetManager g_AssetManager;
const std::string MeshComponent::name = "Mesh";
MeshComponent::MeshComponent()
: vao(0), indexCount(0), textureID(0), MeshPath("assets/models/DefaultMesh.obj")
: vao(0), indexCount(0), MeshPath("assets/models/DefaultMesh.obj")
{
}
@ -24,73 +24,111 @@ const std::string &MeshComponent::GetStaticName()
return name;
}
void MeshComponent::Update(float deltaTime)
{
return;
}
YAML::Node MeshComponent::Serialize()
{
YAML::Node node;
node["vao"] = static_cast<int>(vao);
node["indexCount"] = static_cast<int>(indexCount);
node["textureID"] = static_cast<int>(textureID);
node["MeshPath"] = static_cast<std::string>(MeshPath);
// 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;
node["MeshPath"] = MeshPath;
return node;
}
void MeshComponent::Deserialize(const YAML::Node &node)
{
if (node["MeshPath"])
{
MeshPath = static_cast<std::string>(node["MeshPath"].as<std::string>());
// g_AssetManager.DebugAssetMap();
MeshPath = node["MeshPath"].as<std::string>();
DEBUG_PRINT("Loading Mesh: %s", MeshPath.c_str());
Model *model = g_AssetManager.loadAsset<Model *>(AssetType::MODEL, MeshPath.c_str());
DEBUG_PRINT("Model loaded successfully with %lld vertices and %lld indices.", model->vertices.size(), model->indices.size());
if (!model)
{
DEBUG_PRINT("Failed to load model: %s", MeshPath.c_str());
return;
}
DEBUG_PRINT("Model loaded successfully with %zu vertices and %zu indices.",
model->vertices.size(), model->indices.size());
// Assign VAO and index count
if (model->vao != 0)
{
vao = model->vao;
}
else if (node["vao"])
{
vao = static_cast<int>(node["vao"].as<int>());
vao = node["vao"].as<int>();
}
if (model->indices.size() != 0)
{
indexCount = model->indices.size();
indexCount = static_cast<GLuint>(model->indices.size());
}
else if (node["indexCount"])
{
indexCount = static_cast<int>(node["indexCount"].as<int>());
indexCount = node["indexCount"].as<int>();
}
if (textureID != 0)
{
textureID = model->textureID;
}
else if (node["textureID"])
// Assign Textures
if (!model->textures.empty())
{
textureID = static_cast<int>(node["textureID"].as<int>());
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);
}
}
}
else
{
if (node["vao"])
{
vao = static_cast<int>(node["vao"].as<int>());
vao = node["vao"].as<int>();
}
if (node["indexCount"])
{
indexCount = static_cast<int>(node["indexCount"].as<int>());
indexCount = node["indexCount"].as<int>();
}
if (node["textureID"])
if (node["textures"])
{
textureID = static_cast<int>(node["textureID"].as<int>());
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);
}
}
}
}

View File

@ -1,4 +1,3 @@
// Mesh.h
#pragma once
@ -7,14 +6,16 @@
#include <GL/glew.h>
#include <glm/glm.hpp>
#include <yaml-cpp/yaml.h>
#include <vector>
#include <string>
#include "Engine/AssetManager.h"
class MeshComponent : public Component
{
public:
GLuint vao = 0; // Vertex Array Object
GLuint indexCount = 0; // Number of indices to draw
GLuint textureID = 0; // The texture handle
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::string MeshPath;
@ -22,6 +23,8 @@ public:
virtual const std::string& GetName() const override;
static const std::string& GetStaticName();
virtual void Update(float deltaTime) override;
// Serialization methods
virtual YAML::Node Serialize() override;
virtual void Deserialize(const YAML::Node& node) override;

View File

@ -88,3 +88,10 @@ void ScriptComponent::Update(float deltaTime)
// Call the Update method of LuaManager
m_LuaManager.Update(deltaTime);
}
void ScriptComponent::Init()
{
// Call the Update method of LuaManager
m_LuaManager.CallLuaFunction("OnInit");
}

View File

@ -26,7 +26,11 @@ public:
// Script management methods
bool Initialize();
void Update(float deltaTime);
virtual void Update(float deltaTime);
void Init();
private:

View File

@ -22,6 +22,12 @@ const std::string& TransformComponent::GetStaticName()
return name;
}
void TransformComponent::Update(float _deltaTime)
{
(void)_deltaTime; // Suppress unused parameter warning
return;
}
YAML::Node TransformComponent::Serialize()
{
YAML::Node node;

View File

@ -12,29 +12,35 @@ public:
glm::vec3 rotation;
glm::vec3 scale;
glm::vec3 GetPosition() const {
glm::vec3 GetPosition() const
{
return position;
}
void SetPosition(float x, float y, float z) {
position = { x, y, z };
void SetPosition(float x, float y, float z)
{
position = {x, y, z};
}
glm::vec3 GetRotation() const {
glm::vec3 GetRotation() const
{
return rotation;
}
void SetRotation(float x, float y, float z) {
rotation = { x, y, z };
void SetRotation(float x, float y, float z)
{
rotation = {x, y, z};
}
TransformComponent();
virtual const std::string& GetName() const override;
static const std::string& GetStaticName();
virtual const std::string &GetName() const override;
static const std::string &GetStaticName();
virtual void Update(float deltaTime) override;
// Serialization methods
virtual YAML::Node Serialize() override;
virtual void Deserialize(const YAML::Node& node) override;
virtual void Deserialize(const YAML::Node &node) override;
private:
static const std::string name;

View File

@ -49,6 +49,10 @@ SceneManager g_SceneManager;
std::vector<std::shared_ptr<GameObject>> g_GameObjects;
std::shared_ptr<CameraComponent> g_RuntimeCameraObject;
int g_GPU_Triangles_drawn_to_screen = 0;
GameObject *g_SelectedObject; // Pointer to the currently selected object
@ -145,51 +149,6 @@ void MyEngine::Run()
DEBUG_PRINT("Transition to Editor");
// Pseudocode:
int newId = g_GameObjects.size();
auto newGameObject = std::make_shared<GameObject>(newId, ("Default"));
DEBUG_PRINT("Created Default GameObject");
newGameObject->AddComponent(std::make_shared<TransformComponent>());
newGameObject->AddComponent(std::make_shared<MeshComponent>());
DEBUG_PRINT("Added Componenets");
// Suppose we loaded a VAO, an EBO with 36 indices for the cube,
// and a texture ID from the asset manager
auto mesh = newGameObject->GetComponent<MeshComponent>();
auto transform = newGameObject->GetComponent<TransformComponent>();
DEBUG_PRINT("Got pointers to Componenets");
if (mesh)
{
// printf("Got Valid Mesh Component\n");
Model *model = g_AssetManager.loadAsset<Model *>(AssetType::MODEL, "assets/models/DefaultMesh.obj");
mesh->vao = model->vao;
mesh->indexCount = model->indices.size();
mesh->textureID = g_AssetManager.loadAsset<GLuint>(AssetType::TEXTURE, "assets/textures/wood.png");
}
else
{
DEBUG_PRINT("Could not find Mesh Component\n");
}
if (transform)
{
// printf("Got Valid Transform Component\n");
transform->position = glm::vec3(0.f, 0.f, 0.f);
transform->rotation = glm::vec3(0.f, 0.5f, 0.f);
transform->scale = glm::vec3(1.f, 1.f, 1.f);
}
else
{
DEBUG_PRINT("Could not find Transform Component");
}
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");
@ -216,7 +175,6 @@ void MyEngine::Run()
DEBUG_PRINT("Model loaded successfully with %lld vertices and %lld indices.", model4->vertices.size(), model4->indices.size());
g_GameObjects.push_back(newGameObject);
DEBUG_PRINT("Put componenent into Global Componenets Subsystem");
// printf("%p\n", &g_GameObjects);
@ -262,12 +220,28 @@ void MyEngine::Run()
if (m_FirstTickGameRunning && m_GameRunning)
{
ScopedTimer timer("SaveScene");
m_FirstTickGameRunning = false;
std::string savePath = createTempFolder().string() + "TesseractEngineTempScene.scene";
DEBUG_PRINT("Save path: %s", savePath.c_str());
g_SceneManager.SaveScene(g_GameObjects, savePath);
ScopedTimer LUA_INIT_timer("GameObjectsScriptInit");
for (auto &Gameobject : g_GameObjects)
{
// Handle Components That Require Updates
std::shared_ptr<ScriptComponent> script = Gameobject->GetComponent<ScriptComponent>();
if (script)
{ // Null Checks
ScopedTimer Lua_timer("GameObjectLuaCall_INIT: " + Gameobject->name); // var has to be named that or it will be redecl
script->Init();
}
}
}
if (!m_FirstTickGameRunning && !m_GameRunning)
@ -291,14 +265,9 @@ void MyEngine::Run()
for (auto &Gameobject : g_GameObjects)
{
// Handle Components That Require Updates
std::shared_ptr<ScriptComponent> script = Gameobject->GetComponent<ScriptComponent>();
if (script)
{ // Null Checks
ScopedTimer timer("GameObjectLuaCall: " + Gameobject->name);
script->Update(frame_delta);
}
Gameobject->Update(frame_delta);
}
}

View File

@ -147,14 +147,61 @@ Shader *LoadShaderFromList(const std::string &path)
return 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
// }
Model *LoadModelFromList(const std::string &path)
GLuint LoadTexture(const std::string &path, const std::string &directory)
{
std::string fullPath = directory + path;
int width, height, channels;
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;
return 0;
}
GLenum format;
if (channels == 1)
format = GL_RED;
else if (channels == 3)
format = GL_RGB;
else if (channels == 4)
format = GL_RGBA;
else
format = GL_RGB; // Default fallback
GLuint textureID;
glGenTextures(1, &textureID);
glBindTexture(GL_TEXTURE_2D, textureID);
glTexImage2D(GL_TEXTURE_2D, 0, format, width, height, 0,
format, GL_UNSIGNED_BYTE, data);
glGenerateMipmap(GL_TEXTURE_2D);
// Set texture parameters
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glBindTexture(GL_TEXTURE_2D, 0);
stbi_image_free(data);
return textureID;
}
Model* LoadModelFromList(const std::string &path)
{
// --------------------------------------------
// Load an OBJ model
@ -164,7 +211,7 @@ Model *LoadModelFromList(const std::string &path)
std::ifstream objFile(path);
if (!objFile.is_open())
{
DEBUG_PRINT("[AssetManager] Failed to open OBJ file: %s\n", path.c_str());
std::cerr << "[AssetManager] Failed to open OBJ file: " << path << std::endl;
return nullptr;
}
@ -173,6 +220,14 @@ Model *LoadModelFromList(const std::string &path)
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("/\\");
if (lastSlash != std::string::npos)
@ -180,12 +235,15 @@ Model *LoadModelFromList(const std::string &path)
else
directory = "";
DEBUG_PRINT("[AssetManager] Asset Directory: %s", directory.c_str());
std::cout << "[AssetManager] Asset Directory: " << directory << std::endl;
std::string line;
std::string mtlFileName;
while (std::getline(objFile, line))
{
if (line.empty() || line[0] == '#')
continue; // Skip empty lines and comments
std::istringstream iss(line);
std::string prefix;
iss >> prefix;
@ -193,8 +251,9 @@ Model *LoadModelFromList(const std::string &path)
{
float x, y, z;
iss >> x >> y >> z;
// Flip the model vertically by inverting the y-axis
temp_positions.push_back(x);
temp_positions.push_back(y);
temp_positions.push_back(-y); // Inverted
temp_positions.push_back(z);
}
else if (prefix == "vt")
@ -208,8 +267,9 @@ Model *LoadModelFromList(const std::string &path)
{
float nx, ny, nz;
iss >> nx >> ny >> nz;
// Invert the y-axis for normals as well
temp_normals.push_back(nx);
temp_normals.push_back(ny);
temp_normals.push_back(-ny); // Inverted
temp_normals.push_back(nz);
}
else if (prefix == "f")
@ -250,7 +310,7 @@ Model *LoadModelFromList(const std::string &path)
faceVertices.emplace_back(vIdx, tIdx, nIdx);
}
// Triangulate if the face has more than 3 vertices (optional)
// 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]));
@ -266,7 +326,6 @@ Model *LoadModelFromList(const std::string &path)
normalIndices.push_back(std::get<2>(faceVertices[i + 1]));
}
}
else if (prefix == "mtllib")
{
iss >> mtlFileName;
@ -276,52 +335,123 @@ Model *LoadModelFromList(const std::string &path)
objFile.close();
// Load MTL file if specified
std::string texturePath;
std::vector<Texture> textures;
if (!mtlFileName.empty())
{
std::ifstream mtlFile(directory + mtlFileName);
if (mtlFile.is_open())
{
while (std::getline(mtlFile, line))
std::string mtlLine;
std::string currentMaterial;
std::unordered_map<std::string, std::string> materialTextures;
while (std::getline(mtlFile, mtlLine))
{
std::istringstream mtlIss(line);
if (mtlLine.empty() || mtlLine[0] == '#')
continue; // Skip comments and empty lines
std::istringstream mtlIss(mtlLine);
std::string mtlPrefix;
mtlIss >> mtlPrefix;
if (mtlPrefix == "map_Kd")
if (mtlPrefix == "newmtl")
{
mtlIss >> texturePath;
break; // Assuming only one texture map for simplicity
mtlIss >> currentMaterial;
}
else if (mtlPrefix == "map_Kd")
{
std::string texturePath;
mtlIss >> texturePath;
if (!texturePath.empty())
{
GLuint texID = LoadTexture(texturePath, directory);
if (texID != 0)
{
Texture texture;
texture.id = texID;
texture.type = "texture_diffuse";
texture.path = texturePath;
textures.push_back(texture);
}
}
}
else if (mtlPrefix == "map_Ks")
{
std::string texturePath;
mtlIss >> texturePath;
if (!texturePath.empty())
{
GLuint texID = LoadTexture(texturePath, directory);
if (texID != 0)
{
Texture texture;
texture.id = texID;
texture.type = "texture_specular";
texture.path = texturePath;
textures.push_back(texture);
}
}
}
else if (mtlPrefix == "map_Bump" || mtlPrefix == "map_bump" || mtlPrefix == "bump")
{
std::string texturePath;
mtlIss >> texturePath;
if (!texturePath.empty())
{
GLuint texID = LoadTexture(texturePath, directory);
if (texID != 0)
{
Texture texture;
texture.id = texID;
texture.type = "texture_normal";
texture.path = texturePath;
textures.push_back(texture);
}
}
}
// Add more texture types as needed
}
mtlFile.close();
}
else
{
DEBUG_PRINT("[AssetManager] Failed to open MTL file: %s", mtlFileName.c_str());
std::cerr << "[AssetManager] Failed to open MTL file: " << mtlFileName << std::endl;
}
}
if (texturePath.empty())
{
DEBUG_PRINT("[AssetManager] No texture found for OBJ: %s", path.c_str());
}
else
{
DEBUG_PRINT("[AssetManager] Texture for OBJ: %s%s", directory.c_str(), texturePath.c_str());
std::cout << "[AssetManager] No MTL file specified for OBJ: " << path << std::endl;
}
if (textures.empty())
{
std::cout << "[AssetManager] No textures found for OBJ: " << path << std::endl;
}
else
{
std::cout << "[AssetManager] Loaded " << textures.size() << " textures for OBJ: " << path << std::endl;
}
// Create Model object
Model *model = new Model();
model->textures = textures;
// Populate vertices
// 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)
{
std::ostringstream keyStream;
keyStream << vertexIndices[i] << "/" << texCoordIndices[i] << "/" << normalIndices[i];
std::string key = keyStream.str();
if (uniqueVertices.find(key) == uniqueVertices.end())
auto it = uniqueVertices.find(key);
if (it == uniqueVertices.end())
{
Vertex vertex;
// OBJ indices are 1-based
@ -329,7 +459,7 @@ Model *LoadModelFromList(const std::string &path)
vertex.position[1] = temp_positions[(vertexIndices[i] - 1) * 3 + 1];
vertex.position[2] = temp_positions[(vertexIndices[i] - 1) * 3 + 2];
if (!temp_texCoords.empty())
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];
@ -340,7 +470,7 @@ Model *LoadModelFromList(const std::string &path)
vertex.texCoord[1] = 0.0f;
}
if (!temp_normals.empty())
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];
@ -360,7 +490,7 @@ Model *LoadModelFromList(const std::string &path)
}
else
{
model->indices.push_back(uniqueVertices[key]);
model->indices.push_back(it->second);
}
}
@ -379,56 +509,17 @@ Model *LoadModelFromList(const std::string &path)
// Vertex positions
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void *)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)));
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)));
glVertexAttribPointer(2, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)(5 * sizeof(float)));
glBindVertexArray(0);
// Load texture if available
if (!texturePath.empty())
{
int width, height, channels;
unsigned char *data = stbi_load((directory + texturePath).c_str(), &width, &height, &channels, 0);
if (!data)
{
DEBUG_PRINT("[AssetManager] stb_image failed to load texture: %s", (directory + texturePath).c_str());
}
else
{
GLenum format = GL_RGBA;
if (channels == 1)
format = GL_RED;
else if (channels == 3)
format = GL_RGB;
// if channels == 4, already GL_RGBA
// The textures are already loaded and stored in the model->textures vector
glGenTextures(1, &model->textureID);
glBindTexture(GL_TEXTURE_2D, model->textureID);
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);
glBindTexture(GL_TEXTURE_2D, 0);
stbi_image_free(data);
}
}
else
{
model->textureID = 0; // No texture
}
// Return the Model pointer as void*
return model;
}

View File

@ -34,17 +34,18 @@ struct Vertex
float normal[3];
};
struct Model
{
// Define a Texture structure
struct Texture {
GLuint id;
std::string type;
std::string path;
};
struct Model {
std::vector<Vertex> vertices;
std::vector<unsigned int> indices;
GLuint vao;
GLuint vbo;
GLuint ebo;
GLuint textureID;
Model()
: vao(0), vbo(0), ebo(0), textureID(0) {}
std::vector<Texture> textures;
GLuint vao, vbo, ebo;
};
// The main AssetManager

View File

@ -220,6 +220,76 @@ void LuaManager::Update(float deltaTime)
}
}
// Update function called every frame
void LuaManager::CallLuaFunction(std::string functionName)
{
if (!m_LuaState)
{
if (g_LoggerWindow)
{
g_LoggerWindow->AddLog("LuaManager: Lua state is not initialized.", std::optional<ImVec4>(ImVec4(1.0f, 0.0f, 0.0f, 1.0f)));
}
else
{
DEBUG_PRINT("LuaManager: Lua state is not initialized.");
}
return;
}
// Push the 'OnUpdate' function onto the stack
lua_getglobal(m_LuaState, functionName.c_str());
if (!lua_isfunction(m_LuaState, -1))
{
DEBUG_PRINT("LuaManager: 'OnUpdate' is not a function.");
return;
}
// Call the function with 0 argument and 0 return values
if (lua_pcall(m_LuaState, 0, 0, 0) != LUA_OK)
{
const char *luaError = lua_tostring(m_LuaState, -1);
if (luaError)
{
std::string errorMsg(luaError);
// Prevent duplicate error logs
if (errorMsg != m_LastErrorMessage)
{
if (g_LoggerWindow)
{
std::string formattedError = "LuaManager Error in " + functionName + ": " + errorMsg;
ImVec4 redColor = ImVec4(1.0f, 0.0f, 0.0f, 1.0f);
g_LoggerWindow->AddLog(formattedError.c_str(), std::optional<ImVec4>(redColor));
}
else
{
DEBUG_PRINT("LuaManager Error in OnUpdate: %s", errorMsg.c_str());
}
m_LastErrorMessage = errorMsg;
}
}
else
{
if (g_LoggerWindow)
{
g_LoggerWindow->AddLog("LuaManager: Unknown error in %s.", std::optional<ImVec4>(ImVec4(1.0f, 0.0f, 0.0f, 1.0f)), functionName.c_str());
}
else
{
DEBUG_PRINT("LuaManager: Unknown error in %s.", functionName.c_str());
}
}
lua_pop(m_LuaState, 1); // Remove error message from stack
return;
}
else
{
// Reset last error message on successful call
m_LastErrorMessage.clear();
}
}
// Binding function to log messages from Lua
int LuaManager::Lua_Engine_Log(lua_State *L)
{
@ -322,7 +392,6 @@ int LuaManager::Lua_GetGameObjectByTag(lua_State *L)
return 1; // Return the GameObject userdata
}
// Binding function to retrieve a Component by name from a GameObject
int LuaManager::Lua_GameObject_GetComponent(lua_State *L)
{
@ -354,7 +423,6 @@ int LuaManager::Lua_GameObject_GetComponent(lua_State *L)
return 1;
}
// Determine which metatable to use based on the component type
if (strcmp(componentNameStr, "Transform") == 0)
{
@ -400,7 +468,6 @@ int LuaManager::Lua_GameObject_GetComponent(lua_State *L)
// Set the metatable for the userdata
lua_setmetatable(L, -2);
return 1; // Return the Component userdata
}
@ -518,7 +585,6 @@ int LuaManager::Lua_TransformComponent_GetRotation(lua_State *L)
return 1; // Return the position table
}
// Binding function to set a TransformComponent's position
int LuaManager::Lua_TransformComponent_SetRotation(lua_State *L)
{
@ -561,31 +627,7 @@ int LuaManager::Lua_TransformComponent_SetRotation(lua_State *L)
return 0; // No return values
}
// Binding function to retrieve a MeshComponent's mesh data
int LuaManager::Lua_MeshComponent_GetMeshData(lua_State *L)
{
// Ensure the first argument is a userdata with MeshComponentMetaTable
MeshComponent **udata = (MeshComponent **)luaL_checkudata(L, 1, "MeshComponentMetaTable");
if (udata == nullptr || *udata == nullptr)
{
lua_pushstring(L, "Invalid MeshComponent.");
lua_error(L);
return 0;
}
// Example: Push mesh data as a table
// Ensure MeshData is defined appropriately in MeshComponent
GLuint ID = (*udata)->textureID; // Assume MeshData is a struct with relevant fields
lua_newtable(L);
lua_pushnumber(L, ID);
lua_setfield(L, -2, "vertexData");
// lua_pushstring(L, ID.indexData.c_str());
// lua_setfield(L, -2, "indexData");
// Add more mesh data fields as needed
return 1; // Return the mesh data table
}
// Binding function to retrieve a ScriptComponent's script path
int LuaManager::Lua_ScriptComponent_GetScriptPath(lua_State *L)
@ -700,10 +742,6 @@ void LuaManager::RegisterMeshComponentMetaTable()
luaL_getmetatable(m_LuaState, "ComponentMetaTable");
lua_setfield(m_LuaState, -2, "__base");
// Add methods specific to MeshComponent
lua_pushcfunction(m_LuaState, Lua_MeshComponent_GetMeshData);
lua_setfield(m_LuaState, -2, "GetMeshData");
// Add more Mesh-specific methods as needed
lua_settable(m_LuaState, -3); // Set __index to the table with methods

View File

@ -55,6 +55,10 @@ public:
*/
void Update(float deltaTime);
void CallLuaFunction(std::string functionName);
private:
// Lua state
std::string ScriptPath;

View File

@ -8,6 +8,7 @@
extern std::vector<GameObject> g_GameObjects;
extern GameObject *g_SelectedObject; // Pointer to the currently selected object
extern std::shared_ptr<CameraComponent> g_RuntimeCameraObject;
extern LoggerWindow *g_LoggerWindow;
@ -73,7 +74,6 @@ void InspectorWindow::Show()
// 2) ADD COMPONENT SECTION
// ===========================
ImGui::Text("Add Component:");
ImGui::SameLine();
@ -154,7 +154,6 @@ void InspectorWindow::Show()
ImGui::Separator();
// ===========================
// 1) TRANSFORM
// ===========================
@ -162,6 +161,7 @@ void InspectorWindow::Show()
std::shared_ptr<TransformComponent> transform = g_SelectedObject->GetComponent<TransformComponent>();
std::shared_ptr<MeshComponent> mesh = g_SelectedObject->GetComponent<MeshComponent>();
std::shared_ptr<ScriptComponent> script = g_SelectedObject->GetComponent<ScriptComponent>();
std::shared_ptr<CameraComponent> camera = g_SelectedObject->GetComponent<CameraComponent>();
// Color the Transform header
@ -376,52 +376,292 @@ void InspectorWindow::Show()
}
}
if (camera)
{
// Styling: Set text color to white for the header
ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(1.0f, 1.0f, 1.0f, 1.0f));
// Create a collapsing header for the Camera component
bool cameraOpen = ImGui::CollapsingHeader("Camera##CamerInspector", ImGuiTreeNodeFlags_DefaultOpen);
ImGui::PopStyleColor(); // Revert text color
if (cameraOpen)
{
// Edit Field of View (FOV)
if (ImGui::InputFloat("Field of View°", &camera->FOV, 1.0f, 10.0f, "%.1f"))
{
// Optionally, validate or clamp FOV values
if (camera->FOV < 1.0f)
camera->FOV = 1.0f;
if (camera->FOV > 179.0f)
camera->FOV = 179.0f;
}
// Edit Near Plane
if (ImGui::InputFloat("Near Plane", &camera->NearPlane, 0.1f, 1.0f, "%.2f"))
{
// Clamp Near Plane to a minimum value to prevent rendering issues
if (camera->NearPlane < 0.1f)
camera->NearPlane = 0.1f;
// Ensure Near Plane is always less than Far Plane
if (camera->NearPlane >= camera->FarPlane)
camera->NearPlane = camera->FarPlane - 0.1f;
}
// Edit Far Plane
if (ImGui::InputFloat("Far Plane", &camera->FarPlane, 10.0f, 100.0f, "%.2f"))
{
// Clamp Far Plane to a minimum value greater than Near Plane
if (camera->FarPlane <= camera->NearPlane)
camera->FarPlane = camera->NearPlane + 0.1f;
}
// Edit Aspect Ratio
if (ImGui::InputFloat("Aspect Ratio", &camera->AspectRatio, 0.01f, 0.1f, "%.2f"))
{
// Optionally, validate or clamp Aspect Ratio values
if (camera->AspectRatio <= 0.0f)
camera->AspectRatio = 1.77f; // Default to 16:9
}
// *** Begin Changed Code ***
// Replace the "Orthographic" Checkbox with a "Perspective" Switch
// Determine if the current camera is in perspective mode
bool isPerspective = camera->IsPerspective;
// Render the switch (styled checkbox to resemble a switch)
ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(4, 2));
if (ImGui::Checkbox("Perspective", &isPerspective))
{
camera->IsPerspective = isPerspective;
if (isPerspective)
{
// Set to Perspective Projection
// Use existing camera properties or set to default values
camera->SetPerspective(camera->FOV, camera->AspectRatio, camera->NearPlane, camera->FarPlane);
}
else
{
// Set to Orthographic Projection
// Define orthographic boundaries based on current aspect ratio or set to default values
float orthoLeft = -camera->AspectRatio;
float orthoRight = camera->AspectRatio;
float orthoBottom = -1.0f;
float orthoTop = 1.0f;
camera->SetOrthographic(orthoLeft, orthoRight, orthoBottom, orthoTop, camera->NearPlane, camera->FarPlane);
}
// Update the global primary camera if needed
g_RuntimeCameraObject = camera;
// Log the projection mode change
std::string projectionMode = isPerspective ? "Perspective" : "Orthographic";
g_LoggerWindow->AddLog("Changed Projection Mode to %s for Camera: %s",
ImVec4(0.0f, 1.0f, 0.0f, 1.0f),
projectionMode.c_str(),
g_SelectedObject->name.c_str());
}
ImGui::PopStyleVar();
// Optional: Add a tooltip for the Perspective switch
if (ImGui::IsItemHovered())
{
ImGui::BeginTooltip();
ImGui::Text("Toggle between Perspective and Orthographic projection modes.");
ImGui::EndTooltip();
}
// *** End Changed Code ***
// Add more camera properties here as needed
ImGui::Spacing();
// Replace the "Set as Primary" Button with a Checkbox
// Determine if the current camera is the primary camera
bool isPrimary = (g_RuntimeCameraObject == camera);
// Render the Checkbox
if (ImGui::Checkbox("Primary", &isPrimary))
{
if (isPrimary)
{
// Assign the current camera as the primary camera
g_RuntimeCameraObject = camera;
camera->DefaultRuntimeCamera = true;
// unset other cameras' DefaultRuntimeCamera flags
//! Not used because I don't want to
/*
for (auto& [name, cam] : allCameras)
{
if (cam != camera)
cam->DefaultRuntimeCamera = false;
}
*/
// Log the event
g_LoggerWindow->AddLog("Set Primary Camera: %s", ImVec4(0.0f, 1.0f, 0.0f, 1.0f), g_SelectedObject->name.c_str());
}
else
{
// If unchecked and this camera was the primary, unset it
if (g_RuntimeCameraObject == camera)
g_RuntimeCameraObject.reset(); // Assuming SharedPtr has a reset method
camera->DefaultRuntimeCamera = false;
// Log the event
g_LoggerWindow->AddLog("Unset Primary Camera: %s", ImVec4(1.0f, 0.0f, 0.0f, 1.0f), g_SelectedObject->name.c_str());
}
}
//// Optional: Indicate if this camera is currently the primary camera
// if (g_RuntimeCameraObject == camera)
//{
// ImGui::SameLine();
// ImGui::TextColored(ImVec4(0.0f, 1.0f, 0.0f, 1.0f), "(Primary)");
// }
}
}
// Inside your RenderWindow.cpp or the relevant ImGui rendering function
if (mesh && g_SelectedObject)
{
// Transform* transform = &g_SelectedObject->transform;
ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(1.0f, 1.0f, 1.0f, 1.0f));
bool meshOpen = ImGui::CollapsingHeader("Mesh##Main", ImGuiTreeNodeFlags_DefaultOpen);
ImGui::PopStyleColor();
// printf("%p\n", &transform);
if (meshOpen)
{
// --- VAO ---
int vao = static_cast<int>(mesh->vao);
if (ImGui::InputInt("vao", &vao, 1, 0))
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("indexCount", &indexCount, 1, 0))
if (ImGui::InputInt("Index Count", &indexCount, 1, 0))
{
mesh->indexCount = static_cast<GLuint>(indexCount);
}
int textureID = static_cast<int>(mesh->textureID);
if (ImGui::InputInt("textureID", &textureID, 1, 0))
{
mesh->textureID = static_cast<GLuint>(textureID);
}
// Define a maximum buffer size
// --- Mesh Path ---
const size_t BUFFER_SIZE = 256;
// Allocate a buffer and initialize it with the current string
char buffer[BUFFER_SIZE];
strncpy(buffer, mesh->MeshPath.c_str(), BUFFER_SIZE - 1);
buffer[BUFFER_SIZE - 1] = '\0'; // Ensure null-termination
// Render the InputText widget
if (ImGui::InputText(mesh->MeshPath.c_str(), buffer, BUFFER_SIZE))
if (ImGui::InputText("Mesh Path", buffer, BUFFER_SIZE))
{
// Update the string if user made changes
mesh->MeshPath = buffer;
// Optionally, trigger reloading the mesh if the path changes
// e.g., g_AssetManager.loadAsset<Model *>(AssetType::MODEL, mesh->MeshPath.c_str());
}
// --- Textures ---
ImGui::Separator();
ImGui::Text("Textures:");
// Display list of textures
float availableWidth = ImGui::GetContentRegionAvail().x;
ImGui::Image(mesh->textureID, ImVec2(availableWidth, availableWidth), ImVec2(0, 0), ImVec2(1, 1));
for (size_t i = 0; i < mesh->textures.size(); ++i)
{
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))
{
// --- Texture Type ---
char typeBuffer[32];
strncpy(typeBuffer, texture.type.c_str(), sizeof(typeBuffer) - 1);
typeBuffer[sizeof(typeBuffer) - 1] = '\0';
if (ImGui::InputText(("Type##" + std::to_string(i)).c_str(), typeBuffer, sizeof(typeBuffer)))
{
texture.type = std::string(typeBuffer);
// Optionally, validate the type or restrict it to certain values
}
// --- 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);
}
// --- Texture Path ---
char pathBuffer[256];
strncpy(pathBuffer, texture.path.c_str(), sizeof(pathBuffer) - 1);
pathBuffer[sizeof(pathBuffer) - 1] = '\0';
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);
}
// --- 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.");
}
// --- 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
}
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
}
}
ImGui::Spacing();
if (script && g_SelectedObject)
@ -444,7 +684,6 @@ void InspectorWindow::Show()
buffer[BUFFER_SIZE - 1] = '\0'; // Ensure null-termination
// Render the InputText widget
if (ImGui::InputText("Script Path", buffer, BUFFER_SIZE))
{
@ -458,6 +697,7 @@ void InspectorWindow::Show()
if (script->Initialize())
{
script->Init();
g_LoggerWindow->AddLog("Reloaded Script: %s", ImVec4(0.0f, 1.0f, 0.0f, 1.0f), script->ScriptPath.c_str());
}
}

View File

@ -13,43 +13,20 @@ ProfilerWindow::ProfilerWindow()
}
// Calculate moving average
std::vector<float> ProfilerWindow::MovingAverage(const std::deque<double>& data, size_t window)
{
std::vector<float> averages;
if (data.size() < window)
window = data.size();
for (size_t i = 0; i <= data.size() - window; ++i)
{
double sum = 0.0;
for (size_t j = i; j < i + window; ++j)
sum += data[j];
averages.push_back(static_cast<float>(sum / window));
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) {
prev = alpha * static_cast<float>(val) + (1.0f - alpha) * prev;
ema.push_back(prev);
}
return averages;
return ema;
}
std::vector<float> ProfilerWindow::ExponentialMovingAverage(const std::deque<double>& data, float alpha)
{
std::vector<float> smoothedData;
if (data.empty())
return smoothedData;
float ema = static_cast<float>(data[0]); // Initialize EMA with the first value
smoothedData.push_back(ema);
for (size_t i = 1; i < data.size(); ++i)
{
ema = alpha * static_cast<float>(data[i]) + (1 - alpha) * ema;
smoothedData.push_back(ema);
}
return smoothedData;
}
// Update the history data structures with the latest profiling data
void ProfilerWindow::UpdateHistory(const std::unordered_map<std::string, ProfileResult>& data, double totalFrameTime)
{
// Update total frame time history
@ -57,8 +34,6 @@ void ProfilerWindow::UpdateHistory(const std::unordered_map<std::string, Profile
if (m_TotalFrameTimeHistory.size() > MaxFrameHistory)
m_TotalFrameTimeHistory.pop_front();
// Debug: Print the size of m_TotalFrameTimeHistory
// Update each function's profiling history
for (const auto& [name, result] : data)
{
@ -74,10 +49,43 @@ void ProfilerWindow::UpdateHistory(const std::unordered_map<std::string, Profile
history.averageTimeHistory.push_back(average);
if (history.averageTimeHistory.size() > ProfileHistory::MaxHistory)
history.averageTimeHistory.pop_front();
// Update call count history
history.callCountHistory.push_back(result.CallCount);
if (history.callCountHistory.size() > ProfileHistory::MaxHistory)
history.callCountHistory.pop_front();
}
// Ensure that functions not present in the current frame retain their last TotalTime and AverageTime
for (auto& [name, history] : m_ProfileHistories)
{
if (data.find(name) == data.end())
{
// Retain last TotalTime and AverageTime by pushing back the last value again
if (!history.totalTimeHistory.empty())
history.totalTimeHistory.push_back(history.totalTimeHistory.back());
else
history.totalTimeHistory.push_back(0.0);
if (!history.averageTimeHistory.empty())
history.averageTimeHistory.push_back(history.averageTimeHistory.back());
else
history.averageTimeHistory.push_back(0.0);
// Update call count history with zero for this frame
history.callCountHistory.push_back(0);
// Maintain history sizes
if (history.totalTimeHistory.size() > ProfileHistory::MaxHistory)
history.totalTimeHistory.pop_front();
if (history.averageTimeHistory.size() > ProfileHistory::MaxHistory)
history.averageTimeHistory.pop_front();
if (history.callCountHistory.size() > ProfileHistory::MaxHistory)
history.callCountHistory.pop_front();
}
}
}
// Render the profiler window with table and graphs
void ProfilerWindow::Show()
{
// Check if it's time to update the profiler data
@ -91,8 +99,8 @@ void ProfilerWindow::Show()
m_LastUpdateTime = now;
}
// Begin ImGui window
ImGui::Begin("Profiler");
// Begin ImGui window with improved styling
ImGui::Begin("Profiler", nullptr, ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_HorizontalScrollbar);
const auto& data = Profiler::Get().GetLastFrameData();
@ -120,62 +128,72 @@ void ProfilerWindow::Show()
}
// Render profiling data table
RenderTable(data);
RenderTable();
// Render profiling graphs
//RenderGraphs();
RenderGraphs();
// Display total frame time (from the last update)
if (!m_TotalFrameTimeHistory.empty())
{
double lastTotalFrameTime = m_TotalFrameTimeHistory.back();
ImGui::Separator();
ImGui::Text("Total Frame Time: %.3f µs", lastTotalFrameTime);
ImGui::TextColored(ImVec4(0.4f, 0.7f, 0.0f, 1.0f), "Total Frame Time: %.3f µs", lastTotalFrameTime);
}
ImGui::End();
}
// Render the profiling data table
void ProfilerWindow::RenderTable(const std::unordered_map<std::string, ProfileResult>& data)
void ProfilerWindow::RenderTable()
{
// Sort functions by total time descending
std::vector<std::pair<std::string, ProfileResult>> sortedData(data.begin(), data.end());
std::sort(sortedData.begin(), sortedData.end(),
[](const std::pair<std::string, ProfileResult>& a, const std::pair<std::string, ProfileResult>& b) -> bool {
return a.second.TotalTime > b.second.TotalTime;
// Collect all profiling histories
std::vector<std::pair<std::string, ProfileHistory>> allData(m_ProfileHistories.begin(), m_ProfileHistories.end());
// 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();
});
// Add a filter input
// Add a filter input with enhanced styling
ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(4, 2));
static char filterBuffer[128] = "";
ImGui::InputText("Filter", filterBuffer, IM_ARRAYSIZE(filterBuffer));
ImGui::InputTextWithHint("##Filter", "Filter functions...", filterBuffer, IM_ARRAYSIZE(filterBuffer));
ImGui::PopStyleVar();
// Convert filter to string
std::string filterStr = filterBuffer;
// Filtered data
std::vector<std::pair<std::string, ProfileResult>> filteredData;
for (const auto& [name, result] : sortedData)
std::vector<std::pair<std::string, ProfileHistory>> filteredData;
for (const auto& [name, history] : allData)
{
if (filterStr.empty() || name.find(filterStr) != std::string::npos)
filteredData.emplace_back(name, result);
filteredData.emplace_back(name, history);
}
// Define threshold for highlighting (e.g., 1000 µs)
const double highlightThreshold = 1000.0;
// Table with sorted data
if (ImGui::BeginTable("ProfilerTable", 4, ImGuiTableFlags_RowBg | ImGuiTableFlags_Borders | ImGuiTableFlags_Resizable))
// Improved table with sorting indicators and better aesthetics
if (ImGui::BeginTable("ProfilerTable", 4, ImGuiTableFlags_RowBg | ImGuiTableFlags_Borders | ImGuiTableFlags_Resizable | ImGuiTableFlags_ScrollY, ImVec2(0, 300)))
{
// Set up columns with sortable headers
ImGui::TableSetupColumn("Function", ImGuiTableColumnFlags_None);
ImGui::TableSetupColumn("Total Time (µs)", ImGuiTableColumnFlags_None);
ImGui::TableSetupColumn("Average Time (µs)", ImGuiTableColumnFlags_None);
ImGui::TableSetupColumn("Calls", ImGuiTableColumnFlags_None);
ImGui::TableSetupColumn("Calls (This Frame)", ImGuiTableColumnFlags_None);
ImGui::TableHeadersRow();
for (const auto& [name, result] : filteredData)
// Alternate row colors for better readability
bool rowBg = false;
for (const auto& [name, history] : filteredData)
{
ImGui::TableNextRow();
rowBg = !rowBg;
if (rowBg)
ImGui::TableSetBgColor(ImGuiTableBgTarget_RowBg0, ImColor(0.1f, 0.1f, 0.1f, 1.0f));
// Function Name with tooltip
ImGui::TableSetColumnIndex(0);
@ -183,70 +201,58 @@ void ProfilerWindow::RenderTable(const std::unordered_map<std::string, ProfileRe
if (ImGui::IsItemHovered())
{
ImGui::BeginTooltip();
ImGui::Text("Total Time: %.3f µs", result.TotalTime);
double average = result.CallCount > 0 ? result.TotalTime / result.CallCount : 0.0;
ImGui::Text("Average Time: %.3f µs", average);
ImGui::Text("Call Count: %d", result.CallCount);
ImGui::TextColored(ImVec4(1.0f, 0.8f, 0.0f, 1.0f), "Function: %s", name.c_str());
ImGui::Text("Total Time: %.3f µs", history.totalTimeHistory.back());
ImGui::Text("Average Time: %.3f µs", history.averageTimeHistory.back());
ImGui::Text("Call Count (this frame): %d", history.callCountHistory.back());
ImGui::EndTooltip();
}
// Total Time with color coding
ImGui::TableSetColumnIndex(1);
if (result.TotalTime > highlightThreshold)
ImGui::TextColored(ImVec4(1.0f, 0.3f, 0.3f, 1.0f), "%.3f", result.TotalTime);
if (history.totalTimeHistory.back() > highlightThreshold)
ImGui::TextColored(ImVec4(1.0f, 0.3f, 0.3f, 1.0f), "%.3f", history.totalTimeHistory.back());
else
ImGui::Text("%.3f", result.TotalTime);
ImGui::Text("%.3f", history.totalTimeHistory.back());
// Average Time
ImGui::TableSetColumnIndex(2);
double average = result.CallCount > 0 ? result.TotalTime / result.CallCount : 0.0;
ImGui::Text("%.3f", average);
ImGui::Text("%.3f", history.averageTimeHistory.back());
// Call Count
// Call Count (This Frame)
ImGui::TableSetColumnIndex(3);
ImGui::Text("%d", result.CallCount);
ImGui::Text("%d", history.callCountHistory.back());
}
ImGui::EndTable();
}
}
void ProfilerWindow::RenderGraphs()
{
ImGui::Separator();
ImGui::Text("Profiling Graphs (Unified Multi-Line Plot)");
const auto& data = Profiler::Get().GetLastFrameData();
std::vector<std::pair<std::string, ProfileResult>> sortedData;
// Collect and sort functions by total time used
for (const auto& [name, result] : data)
{
sortedData.emplace_back(name, result);
}
ImGui::TextColored(ImVec4(0.0f, 0.7f, 0.9f, 1.0f), "Profiling Graphs (Top 5 Functions)");
// 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, ProfileResult>& a, const std::pair<std::string, ProfileResult>& b) -> bool {
return a.second.TotalTime > b.second.TotalTime;
});
[](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
// Prepare data for the unified plot
// Prepare data for the unified plot with EMA smoothing
std::vector<std::vector<float>> plotData(displayCount);
std::vector<std::string> functionNames;
float alpha = 0.2f; // Smoothing factor for EMA
for (size_t i = 0; i < displayCount; ++i)
{
const auto& [name, result] = sortedData[i];
const auto& [name, history] = sortedData[i];
functionNames.push_back(name);
// Smooth each function's data using EMA
const auto& history = m_ProfileHistories[name];
plotData[i] = ExponentialMovingAverage(history.totalTimeHistory, alpha);
}
@ -265,33 +271,40 @@ void ProfilerWindow::RenderGraphs()
// Prepare the combined graph
if (maxHistorySize > 0)
{
std::vector<float> combinedGraph(maxHistorySize, 0.0f);
// Render a single unified graph with multi-line data
ImVec2 graphSize = ImVec2(0, 200); // Graph dimensions
ImGui::PlotLines(
"##UnifiedGraph",
[](void* data, int idx) -> float {
auto* plotData = static_cast<std::vector<std::vector<float>>*>(data);
float value = 0.0f;
// Begin child region for better layout control
ImGui::BeginChild("GraphChild", graphSize, false, ImGuiWindowFlags_NoScrollbar);
for (const auto& series : *plotData)
{
if (idx < series.size())
value += series[idx];
}
// Plot each function's history as separate lines with unique colors
for (size_t i = 0; i < displayCount; ++i)
{
ImU32 color = ImColor::HSV(static_cast<float>(i) / displayCount, 0.6f, 0.9f);
ImGui::PushStyleColor(ImGuiCol_PlotLines, color);
ImGui::PlotLines(
functionNames[i].c_str(),
plotData[i].data(),
static_cast<int>(plotData[i].size()),
0,
nullptr,
0.0f,
static_cast<float>(maxValue) * 1.1f, // Add some padding to the max value
ImVec2(0, 100)
);
ImGui::PopStyleColor();
}
return value;
},
static_cast<void*>(&plotData), static_cast<int>(maxHistorySize), 0, nullptr, 0.0f, maxValue, graphSize);
ImGui::EndChild();
// Add a legend for the lines
ImGui::Separator();
for (size_t i = 0; i < functionNames.size(); ++i)
{
ImVec4 lineColor = ImVec4(0.2f + 0.2f * i, 0.2f, 1.0f - 0.2f * i, 1.0f);
ImGui::TextColored(lineColor, "%s", functionNames[i].c_str());
ImVec4 lineColor = ImColor::HSV(static_cast<float>(i) / displayCount, 0.6f, 0.9f);
ImGui::SameLine();
ImGui::ColorButton(("##Color" + std::to_string(i)).c_str(), lineColor, ImGuiColorEditFlags_NoTooltip | ImGuiColorEditFlags_NoDragDrop | ImGuiColorEditFlags_NoBorder, ImVec2(10, 10));
ImGui::SameLine();
ImGui::TextUnformatted(functionNames[i].c_str());
}
}
}

View File

@ -9,35 +9,31 @@
class ProfilerWindow
{
public:
ProfilerWindow();
~ProfilerWindow() = default;
// Render the profiler window
void UpdateHistory(const std::unordered_map<std::string, ProfileResult> &data, double totalFrameTime);
void Show();
void RenderTable();
void RenderGraphs();
private:
struct ProfileHistory
{
std::deque<double> totalTimeHistory;
std::deque<double> averageTimeHistory;
static const size_t MaxHistory = 100;
std::deque<double> totalTimeHistory; // Last N total times
std::deque<double> averageTimeHistory; // Last N average times
std::deque<int> callCountHistory; // Last N call counts
};
std::unordered_map<std::string, ProfileHistory> m_ProfileHistories;
std::deque<double> m_TotalFrameTimeHistory;
static const size_t MaxFrameHistory = 100;
// Timing variables for update throttling
double m_UpdateInterval; // Interval in seconds (0.1)
std::chrono::steady_clock::time_point m_LastUpdateTime;
double m_UpdateInterval; // In seconds
// Helper functions
void UpdateHistory(const std::unordered_map<std::string, ProfileResult> &data, double totalFrameTime);
void RenderTable(const std::unordered_map<std::string, ProfileResult> &data);
void RenderGraphs();
// Helper for data smoothing
std::vector<float> MovingAverage(const std::deque<double> &data, size_t window);
// Helper function for Exponential Moving Average
std::vector<float> ExponentialMovingAverage(const std::deque<double> &data, float alpha);
};

View File

@ -28,6 +28,10 @@ extern std::vector<std::shared_ptr<GameObject>> g_GameObjects;
extern AssetManager g_AssetManager;
extern std::shared_ptr<CameraComponent> g_RuntimeCameraObject;
extern int g_GPU_Triangles_drawn_to_screen;
// Example cube data (position + UVs)
@ -284,7 +288,7 @@ void RenderWindow::Show(bool *GameRunning)
m_LastHeight = h;
}
RenderSceneToFBO();
RenderSceneToFBO(GameRunning);
ImGui::Image(m_FBO.GetTextureID(), size, ImVec2(0, 0), ImVec2(1, 1));
}
@ -361,64 +365,104 @@ void RenderWindow::InitGLResources()
// ----------------------------------------------------
}
void RenderWindow::RenderSceneToFBO()
{
m_RotationAngle += 0.001f; // spin per frame
void CheckOpenGLError(const std::string &location)
{
GLenum err;
bool hasError = false;
while ((err = glGetError()) != GL_NO_ERROR)
{
std::cerr << "[OpenGL Error] (" << err << ") at " << location << std::endl;
hasError = true;
}
if (hasError)
{
// Optionally, you can throw an exception or handle the error as needed
}
}
void RenderWindow::RenderSceneToFBO(bool *GameRunning)
{
m_RotationAngle += 0.001f; // Spin per frame
// Bind the FBO
m_FBO.Bind();
glViewport(0, 0, m_LastWidth, m_LastHeight);
CheckOpenGLError("After glViewport");
glEnable(GL_DEPTH_TEST);
CheckOpenGLError("After glEnable(GL_DEPTH_TEST)");
glClearColor(0.f, 0.f, 0.f, 1.f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
CheckOpenGLError("After glClear");
// Use our loaded shader
if (!m_ShaderPtr)
{
std::cerr << "[RenderWindow] Shader pointer is null. Cannot render." << std::endl;
m_FBO.Unbind();
return; // Can't render without a shader
}
m_ShaderPtr->Use();
GLuint programID = m_ShaderPtr->GetProgramID();
CheckOpenGLError("After shader use");
// 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);
std::shared_ptr<CameraComponent> activeCamera = nullptr;
glm::mat4 view;
glm::mat4 proj;
if (*GameRunning && g_RuntimeCameraObject)
{
activeCamera = g_RuntimeCameraObject;
}
// Ensure that an active camera is available
if (activeCamera)
{
// Obtain view and projection matrices from the active camera
view = activeCamera->GetViewMatrix();
proj = activeCamera->GetProjectionMatrix();
}
else
{
// Fallback to default view and projection if no camera is available
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;
proj = glm::perspective(glm::radians(CAM_FOV), aspect, CAM_NEAR_PLAIN, CAM_FAR_PLAIN);
}
// Iterate over each GameObject and render it
for (auto &obj : g_GameObjects)
{
// -----------------------------------
// 1) Build MVP from transform
// -----------------------------------
glm::mat4 model = glm::mat4(1.f);
std::shared_ptr<TransformComponent> transform = obj->GetComponent<TransformComponent>();
std::shared_ptr<MeshComponent> mesh = obj->GetComponent<MeshComponent>();
if (transform && mesh)
{
// Validate VAO
if (mesh->vao == 0)
{
std::cerr << "[RenderWindow] Warning: Mesh VAO is not initialized." << std::endl;
continue;
}
// Translate
// Update triangle count
g_GPU_Triangles_drawn_to_screen += static_cast<int>(mesh->indexCount);
// Apply transformations
model = glm::translate(model, transform->position);
// Rotate around X, Y, Z
// transform->rotation.x += m_RotationAngle;
model = glm::rotate(model, glm::radians(transform->rotation.x), glm::vec3(1.f, 0.f, 0.f));
model = glm::rotate(model, glm::radians(transform->rotation.y), glm::vec3(0.f, 1.f, 0.f));
model = glm::rotate(model, glm::radians(transform->rotation.z), glm::vec3(0.f, 0.f, 1.f));
// Scale
model = glm::scale(model, transform->scale);
// Compute MVP
@ -426,31 +470,111 @@ void RenderWindow::RenderSceneToFBO()
// Pass MVP to the shader
GLint mvpLoc = glGetUniformLocation(programID, "uMVP");
glUniformMatrix4fv(mvpLoc, 1, GL_FALSE, glm::value_ptr(mvp));
if(mvpLoc != -1)
{
glUniformMatrix4fv(mvpLoc, 1, GL_FALSE, glm::value_ptr(mvp));
}
else
{
std::cerr << "[RenderWindow] Warning: Uniform 'uMVP' not found in shader." << std::endl;
}
// Pass Model matrix to the shader
GLint modelLoc = glGetUniformLocation(programID, "uModel");
if(modelLoc != -1)
{
glUniformMatrix4fv(modelLoc, 1, GL_FALSE, glm::value_ptr(model));
}
else
{
std::cerr << "[RenderWindow] Warning: Uniform 'uModel' not found in shader." << std::endl;
}
// -----------------------------------
// 2) Bind the object's texture
// 2) Bind the object's diffuse textures
// -----------------------------------
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, mesh->textureID);
// 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;
// Set the sampler uniform to texture unit 0
GLint texLoc = glGetUniformLocation(programID, "uTexture");
glUniform1i(texLoc, 0);
// Iterate through all textures and bind those with type "texture_diffuse"
for (const auto &texture : mesh->textures)
{
if (texture.type == "texture_diffuse")
{
if (textureUnit >= MAX_DIFFUSE)
{
std::cerr << "[RenderWindow] Warning: Exceeded maximum number of diffuse textures ("
<< MAX_DIFFUSE << ") for shader." << std::endl;
break; // Prevent exceeding the array bounds in the shader
}
// Activate the appropriate texture unit
glActiveTexture(GL_TEXTURE0 + textureUnit);
glBindTexture(GL_TEXTURE_2D, texture.id);
CheckOpenGLError("After glBindTexture");
// 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);
CheckOpenGLError("After glUniform1i for texture");
}
else
{
std::cerr << "[RenderWindow] Warning: Uniform '" << uniformName
<< "' not found in shader." << std::endl;
}
textureUnit++;
}
}
// 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)
{
glUniform1i(texLoc, 0); // Assign texture unit 0 (ensure texture 0 is a valid default)
CheckOpenGLError("After glUniform1i for default texture");
}
}
// Set the number of active diffuse textures
GLint numDiffuseLoc = glGetUniformLocation(programID, "uNumDiffuseTextures");
if(numDiffuseLoc != -1)
{
glUniform1i(numDiffuseLoc, textureUnit);
CheckOpenGLError("After glUniform1i for uNumDiffuseTextures");
}
else
{
std::cerr << "[RenderWindow] Warning: Uniform 'uNumDiffuseTextures' not found in shader." << std::endl;
}
// -----------------------------------
// 3) Draw the object's mesh
// -----------------------------------
glBindVertexArray(mesh->vao);
glDrawElements(GL_TRIANGLES, mesh->indexCount, GL_UNSIGNED_INT, nullptr);
// Unbind for cleanliness
glBindVertexArray(0);
glBindTexture(GL_TEXTURE_2D, 0);
CheckOpenGLError("After glDrawElements");
// Reset active texture
glActiveTexture(GL_TEXTURE0);
CheckOpenGLError("After glActiveTexture(GL_TEXTURE0)");
}
}
// Cleanup
glUseProgram(0);
CheckOpenGLError("After glUseProgram(0)");
m_FBO.Unbind();
CheckOpenGLError("After FBO Unbind");
}

View File

@ -12,7 +12,7 @@ public:
private:
void InitGLResources();
void RenderSceneToFBO();
void RenderSceneToFBO(bool *GameRunning);
// Offscreen render target
FBO m_FBO;