Compare commits
2 Commits
1af62d6484
...
b690c63479
Author | SHA1 | Date | |
---|---|---|---|
|
b690c63479 | ||
|
8d255731e6 |
14
README.md
14
README.md
@ -6,6 +6,20 @@ A 3D Game engine for Small to Medium-sized games with a LUA Scripting interface.
|
|||||||
|
|
||||||
### Note: These screenshots are sorted by version.
|
### Note: These screenshots are sorted by version.
|
||||||
|
|
||||||
|
|
||||||
|
#### 0.0.68
|
||||||
|
- Added Script Component
|
||||||
|
- Added Simple Lua editor (W.I.P)
|
||||||
|
- Added Lua Binding
|
||||||
|
- `Engine.GetGameObjectByTag("")`
|
||||||
|
- `Component::GetComponent(")`
|
||||||
|
- `Engine.Log("")`
|
||||||
|
- `Transform:SetPosition(vec3)`
|
||||||
|
- `Transform:SetRotation(vec3)`
|
||||||
|
|
||||||
|
![](./assets/images/SS-Dev2_1.png)
|
||||||
|
|
||||||
|
|
||||||
#### 0.0.68
|
#### 0.0.68
|
||||||
- Added Script Component
|
- Added Script Component
|
||||||
- Added Simple Lua editor (W.I.P)
|
- Added Simple Lua editor (W.I.P)
|
||||||
|
BIN
assets/images/SS-Dev2_2.png
Normal file
BIN
assets/images/SS-Dev2_2.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 646 KiB |
95
assets/scripts/BouncingItem.lua
Normal file
95
assets/scripts/BouncingItem.lua
Normal file
@ -0,0 +1,95 @@
|
|||||||
|
-- script.lua
|
||||||
|
local Math = require("math") -- Require the enhanced math module
|
||||||
|
|
||||||
|
-- Variables to track elapsed time and rotation
|
||||||
|
local elapsedTime = 0
|
||||||
|
local rotationSpeed = 90 -- Degrees per second for spinning
|
||||||
|
local new_rotation = 0
|
||||||
|
|
||||||
|
-- Variables for bobbing effect
|
||||||
|
local initial_position = {x = 0, y = 0, z = 0} -- To store the gun's initial position
|
||||||
|
local bobAmplitude = 0.1 -- Amplitude of the bobbing (units)
|
||||||
|
local bobFrequency = 0.5 -- Frequency of the bobbing (oscillations per second)
|
||||||
|
|
||||||
|
-- Reference to the Gun GameObject and its Transform component
|
||||||
|
local gun = nil
|
||||||
|
local transform = nil
|
||||||
|
|
||||||
|
local TAU = 6.283185307179586
|
||||||
|
|
||||||
|
|
||||||
|
-- Update function called every frame
|
||||||
|
function OnUpdate(deltaTime)
|
||||||
|
-- Ensure that the Gun and its Transform component are valid
|
||||||
|
if not gun then
|
||||||
|
gun = Engine.GetGameObjectByTag("Gun")
|
||||||
|
if gun then
|
||||||
|
transform = gun:GetComponent("Transform")
|
||||||
|
if transform then
|
||||||
|
local pos = transform:GetPosition()
|
||||||
|
initial_position = {x = pos.x, y = pos.y, z = pos.z}
|
||||||
|
Engine.Log("Gun found and initial position updated.", {1, 1, 1, 1})
|
||||||
|
else
|
||||||
|
Engine.Log("Transform component not found on Gun.", {1, 1, 0, 1})
|
||||||
|
return
|
||||||
|
end
|
||||||
|
else
|
||||||
|
Engine.Log("Gun GameObject still not found.", {1, 1, 0, 1})
|
||||||
|
return
|
||||||
|
end
|
||||||
|
elseif not transform then
|
||||||
|
transform = gun:GetComponent("Transform")
|
||||||
|
if transform then
|
||||||
|
local pos = transform:GetPosition()
|
||||||
|
initial_position = {x = pos.x, y = pos.y, z = pos.z}
|
||||||
|
Engine.Log("Transform component found and initial position updated.", {1, 1, 1, 1})
|
||||||
|
else
|
||||||
|
Engine.Log("Transform component still not found on Gun.", {1, 1, 0, 1})
|
||||||
|
return
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Increment elapsed time
|
||||||
|
elapsedTime = elapsedTime + deltaTime
|
||||||
|
|
||||||
|
-- === Spinning the Gun ===
|
||||||
|
-- Update the rotation angle based on rotationSpeed and deltaTime
|
||||||
|
new_rotation = new_rotation + (deltaTime * rotationSpeed)
|
||||||
|
|
||||||
|
-- Keep the rotation angle within 0-360 degrees to prevent overflow
|
||||||
|
if new_rotation >= 360 then
|
||||||
|
new_rotation = new_rotation - 360
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Define the new rotation (spinning around the Y-axis)
|
||||||
|
local rotation = {
|
||||||
|
x = -180, -- Preserving existing rotation on X-axis
|
||||||
|
y = new_rotation, -- Updated rotation on Y-axis for spinning
|
||||||
|
z = 0 -- Preserving existing rotation on Z-axis
|
||||||
|
}
|
||||||
|
|
||||||
|
-- Apply the new rotation to the Transform component
|
||||||
|
transform:SetRotation(rotation)
|
||||||
|
|
||||||
|
-- === Bobbing the Gun Up and Down ===
|
||||||
|
-- Calculate the bobbing offset using a sine wave
|
||||||
|
local bobOffset = bobAmplitude * math.sin(TAU * bobFrequency * elapsedTime)
|
||||||
|
|
||||||
|
-- Define the new position by adding the bobbing offset to the initial Y position
|
||||||
|
local new_position = {
|
||||||
|
x = initial_position.x, -- No change on X-axis
|
||||||
|
y = initial_position.y + bobOffset, -- Bouncing up and down on Y-axis
|
||||||
|
z = initial_position.z -- No change on Z-axis
|
||||||
|
}
|
||||||
|
|
||||||
|
-- Apply the new position to the Transform component
|
||||||
|
transform:SetPosition(new_position)
|
||||||
|
|
||||||
|
-- === Optional: Log Current Rotation and Position ===
|
||||||
|
-- Uncomment the following lines if you wish to log the gun's current rotation and position
|
||||||
|
-- local current_rotation = transform:GetRotation()
|
||||||
|
-- Engine.Log(string.format("Gun Rotation: (X: %.2f, Y: %.2f, Z: %.2f)", current_rotation.x, current_rotation.y, current_rotation.z), {1, 1, 1, 1})
|
||||||
|
|
||||||
|
-- local current_position = transform:GetPosition()
|
||||||
|
-- Engine.Log(string.format("Gun Position: (X: %.2f, Y: %.2f, Z: %.2f)", current_position.x, current_position.y, current_position.z), {1, 1, 1, 1})
|
||||||
|
end
|
@ -2,9 +2,12 @@
|
|||||||
|
|
||||||
-- Math constants
|
-- Math constants
|
||||||
local MathConstants = {
|
local MathConstants = {
|
||||||
PI = 3.14159,
|
PI = 3.141592653589793,
|
||||||
E = 2.71828,
|
E = 2.718281828459045,
|
||||||
TAU = 6.28318 -- 2 * PI
|
TAU = 6.283185307179586, -- 2 * PI
|
||||||
|
HALF_PI = 1.5707963267948966, -- PI / 2
|
||||||
|
SQRT2 = 1.4142135623730951, -- Square root of 2
|
||||||
|
LN2 = 0.6931471805599453 -- Natural log of 2
|
||||||
}
|
}
|
||||||
|
|
||||||
-- Basic math functions
|
-- Basic math functions
|
||||||
@ -18,40 +21,284 @@ function MathFunctions.cube(x)
|
|||||||
return x * x * x
|
return x * x * x
|
||||||
end
|
end
|
||||||
|
|
||||||
function MathFunctions.max(a, b)
|
function MathFunctions.max(...)
|
||||||
return (a > b) and a or b
|
local args = {...}
|
||||||
|
local maxVal = args[1]
|
||||||
|
for i = 2, #args do
|
||||||
|
if args[i] > maxVal then
|
||||||
|
maxVal = args[i]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return maxVal
|
||||||
end
|
end
|
||||||
|
|
||||||
function MathFunctions.min(a, b)
|
function MathFunctions.min(...)
|
||||||
return (a < b) and a or b
|
local args = {...}
|
||||||
|
local minVal = args[1]
|
||||||
|
for i = 2, #args do
|
||||||
|
if args[i] < minVal then
|
||||||
|
minVal = args[i]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return minVal
|
||||||
end
|
end
|
||||||
|
|
||||||
function MathFunctions.clamp(value, minValue, maxValue)
|
function MathFunctions.clamp(value, minValue, maxValue)
|
||||||
if value < minValue then
|
return MathFunctions.max(minValue, MathFunctions.min(value, maxValue))
|
||||||
return minValue
|
end
|
||||||
elseif value > maxValue then
|
|
||||||
return maxValue
|
function MathFunctions.lerp(a, b, t)
|
||||||
else
|
return a + (b - a) * t
|
||||||
return value
|
end
|
||||||
end
|
|
||||||
|
function MathFunctions.is_close(a, b, tolerance)
|
||||||
|
tolerance = tolerance or 1e-9
|
||||||
|
return MathFunctions.abs(a - b) <= tolerance
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Optimized absolute value function
|
||||||
|
function MathFunctions.abs(x)
|
||||||
|
return (x < 0) and -x or x
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Trigonometric functions
|
-- Trigonometric functions
|
||||||
local TrigFunctions = {}
|
local TrigFunctions = {}
|
||||||
|
|
||||||
function TrigFunctions.deg_to_rad(degrees)
|
-- Manual definitions of hyperbolic functions
|
||||||
return degrees * (MathConstants.PI / 180)
|
function TrigFunctions.sinh(x)
|
||||||
|
return (math.exp(x) - math.exp(-x)) / 2
|
||||||
end
|
end
|
||||||
|
|
||||||
function TrigFunctions.rad_to_deg(radians)
|
function TrigFunctions.cosh(x)
|
||||||
return radians * (180 / MathConstants.PI)
|
return (math.exp(x) + math.exp(-x)) / 2
|
||||||
end
|
end
|
||||||
|
|
||||||
|
function TrigFunctions.tanh(x)
|
||||||
|
return (math.exp(x) - math.exp(-x)) / (math.exp(x) + math.exp(-x))
|
||||||
|
end
|
||||||
|
|
||||||
|
function TrigFunctions.asinh(x)
|
||||||
|
return math.log(x + math.sqrt(x * x + 1))
|
||||||
|
end
|
||||||
|
|
||||||
|
function TrigFunctions.acosh(x)
|
||||||
|
return math.log(x + math.sqrt(x * x - 1))
|
||||||
|
end
|
||||||
|
|
||||||
|
function TrigFunctions.atanh(x)
|
||||||
|
return 0.5 * math.log((1 + x) / (1 - x))
|
||||||
|
end
|
||||||
|
|
||||||
|
function TrigFunctions.sin(x)
|
||||||
|
return math.sin(x)
|
||||||
|
end
|
||||||
|
|
||||||
|
function TrigFunctions.cos(x)
|
||||||
|
return math.cos(x)
|
||||||
|
end
|
||||||
|
|
||||||
|
function TrigFunctions.tan(x)
|
||||||
|
return math.tan(x)
|
||||||
|
end
|
||||||
|
|
||||||
|
function TrigFunctions.atan2(y, x)
|
||||||
|
return math.atan2(y, x)
|
||||||
|
end
|
||||||
|
|
||||||
|
function TrigFunctions.hypot(x, y)
|
||||||
|
return math.sqrt(x * x + y * y)
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Angle normalization and utilities
|
||||||
|
function TrigFunctions.normalize_angle_rad(angle)
|
||||||
|
angle = angle % MathConstants.TAU
|
||||||
|
if angle < 0 then
|
||||||
|
angle = angle + MathConstants.TAU
|
||||||
|
end
|
||||||
|
return angle
|
||||||
|
end
|
||||||
|
|
||||||
|
function TrigFunctions.normalize_angle_pi(angle)
|
||||||
|
angle = angle % MathConstants.TAU
|
||||||
|
if angle <= -MathConstants.PI then
|
||||||
|
angle = angle + MathConstants.TAU
|
||||||
|
elseif angle > MathConstants.PI then
|
||||||
|
angle = angle - MathConstants.TAU
|
||||||
|
end
|
||||||
|
return angle
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Exponential and logarithmic functions
|
||||||
|
local ExpFunctions = {}
|
||||||
|
|
||||||
|
function ExpFunctions.exp(x)
|
||||||
|
return math.exp(x)
|
||||||
|
end
|
||||||
|
|
||||||
|
function ExpFunctions.log(x, base)
|
||||||
|
if base then
|
||||||
|
return math.log(x) / math.log(base)
|
||||||
|
end
|
||||||
|
return math.log(x)
|
||||||
|
end
|
||||||
|
|
||||||
|
function ExpFunctions.pow(base, exponent)
|
||||||
|
return base ^ exponent
|
||||||
|
end
|
||||||
|
|
||||||
|
function ExpFunctions.sqrt(x)
|
||||||
|
return math.sqrt(x)
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Random utility functions
|
||||||
|
local RandomFunctions = {}
|
||||||
|
|
||||||
|
function RandomFunctions.random(min, max)
|
||||||
|
if min and max then
|
||||||
|
return math.random() * (max - min) + min
|
||||||
|
elseif min then
|
||||||
|
return math.random() * min
|
||||||
|
else
|
||||||
|
return math.random()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function RandomFunctions.random_int(min, max)
|
||||||
|
return math.random(min, max)
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Statistical functions
|
||||||
|
local StatFunctions = {}
|
||||||
|
|
||||||
|
-- Calculate the mean of a list of numbers
|
||||||
|
function StatFunctions.mean(numbers)
|
||||||
|
local sum = 0
|
||||||
|
for _, num in ipairs(numbers) do
|
||||||
|
sum = sum + num
|
||||||
|
end
|
||||||
|
return sum / #numbers
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Calculate the median of a list of numbers
|
||||||
|
function StatFunctions.median(numbers)
|
||||||
|
table.sort(numbers)
|
||||||
|
local n = #numbers
|
||||||
|
if n % 2 == 1 then
|
||||||
|
return numbers[math.ceil(n / 2)]
|
||||||
|
else
|
||||||
|
return (numbers[n / 2] + numbers[(n / 2) + 1]) / 2
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Calculate the mode of a list of numbers
|
||||||
|
function StatFunctions.mode(numbers)
|
||||||
|
local counts = {}
|
||||||
|
local max_count = 0
|
||||||
|
local mode_val = numbers[1]
|
||||||
|
for _, num in ipairs(numbers) do
|
||||||
|
counts[num] = (counts[num] or 0) + 1
|
||||||
|
if counts[num] > max_count then
|
||||||
|
max_count = counts[num]
|
||||||
|
mode_val = num
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return mode_val
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Calculate the variance of a list of numbers
|
||||||
|
function StatFunctions.variance(numbers)
|
||||||
|
local mean_val = StatFunctions.mean(numbers)
|
||||||
|
local sum_sq_diff = 0
|
||||||
|
for _, num in ipairs(numbers) do
|
||||||
|
sum_sq_diff = sum_sq_diff + (num - mean_val) ^ 2
|
||||||
|
end
|
||||||
|
return sum_sq_diff / #numbers
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Calculate the standard deviation of a list of numbers
|
||||||
|
function StatFunctions.stddev(numbers)
|
||||||
|
return math.sqrt(StatFunctions.variance(numbers))
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Advanced mathematical functions
|
||||||
|
local AdvancedMath = {}
|
||||||
|
|
||||||
|
-- Calculate factorial of n
|
||||||
|
function AdvancedMath.factorial(n)
|
||||||
|
assert(n >= 0 and math.floor(n) == n, "Factorial is only defined for non-negative integers.")
|
||||||
|
if n == 0 or n == 1 then
|
||||||
|
return 1
|
||||||
|
else
|
||||||
|
return n * AdvancedMath.factorial(n - 1)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Calculate permutations P(n, k)
|
||||||
|
function AdvancedMath.permutation(n, k)
|
||||||
|
assert(n >= 0 and k >= 0 and math.floor(n) == n and math.floor(k) == k, "Permutation requires non-negative integers.")
|
||||||
|
if k > n then
|
||||||
|
return 0
|
||||||
|
end
|
||||||
|
return AdvancedMath.factorial(n) / AdvancedMath.factorial(n - k)
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Calculate combinations C(n, k)
|
||||||
|
function AdvancedMath.combination(n, k)
|
||||||
|
assert(n >= 0 and k >= 0 and math.floor(n) == n and math.floor(k) == k, "Combination requires non-negative integers.")
|
||||||
|
if k > n then
|
||||||
|
return 0
|
||||||
|
end
|
||||||
|
return AdvancedMath.factorial(n) / (AdvancedMath.factorial(k) * AdvancedMath.factorial(n - k))
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Calculate the Greatest Common Divisor using Euclidean algorithm
|
||||||
|
function AdvancedMath.gcd(a, b)
|
||||||
|
a = math.abs(a)
|
||||||
|
b = math.abs(b)
|
||||||
|
while b ~= 0 do
|
||||||
|
a, b = b, a % b
|
||||||
|
end
|
||||||
|
return a
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Calculate the Least Common Multiple
|
||||||
|
function AdvancedMath.lcm(a, b)
|
||||||
|
a = math.abs(a)
|
||||||
|
b = math.abs(b)
|
||||||
|
if a == 0 or b == 0 then
|
||||||
|
return 0
|
||||||
|
end
|
||||||
|
return (a * b) / AdvancedMath.gcd(a, b)
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Numerical approximation of the derivative of a function f at point x
|
||||||
|
function AdvancedMath.derivative(f, x, h)
|
||||||
|
h = h or 1e-5
|
||||||
|
return (f(x + h) - f(x - h)) / (2 * h)
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Numerical approximation of the integral of a function f from a to b using the trapezoidal rule
|
||||||
|
function AdvancedMath.integral(f, a, b, n)
|
||||||
|
n = n or 1000
|
||||||
|
local h = (b - a) / n
|
||||||
|
local sum = 0.5 * (f(a) + f(b))
|
||||||
|
for i = 1, n - 1 do
|
||||||
|
sum = sum + f(a + i * h)
|
||||||
|
end
|
||||||
|
return sum * h
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Statistical and Advanced Math Functions can be grouped similarly
|
||||||
|
|
||||||
-- Export the math module
|
-- Export the math module
|
||||||
local Math = {
|
local Math = {
|
||||||
constants = MathConstants,
|
constants = MathConstants,
|
||||||
functions = MathFunctions,
|
functions = MathFunctions,
|
||||||
trig = TrigFunctions
|
trig = TrigFunctions,
|
||||||
|
exp = ExpFunctions,
|
||||||
|
random = RandomFunctions,
|
||||||
|
stats = StatFunctions,
|
||||||
|
advanced = AdvancedMath
|
||||||
}
|
}
|
||||||
|
|
||||||
return Math
|
return Math
|
||||||
|
91
imgui.ini
91
imgui.ini
@ -18,7 +18,7 @@ DockId=0x00000002,0
|
|||||||
Pos=374,27
|
Pos=374,27
|
||||||
Size=1212,770
|
Size=1212,770
|
||||||
Collapsed=0
|
Collapsed=0
|
||||||
DockId=0x0000000D,0
|
DockId=0x0000001B,0
|
||||||
|
|
||||||
[Window][Performance]
|
[Window][Performance]
|
||||||
Pos=8,774
|
Pos=8,774
|
||||||
@ -48,7 +48,7 @@ DockId=0x0000000B,0
|
|||||||
Pos=374,27
|
Pos=374,27
|
||||||
Size=1202,849
|
Size=1202,849
|
||||||
Collapsed=0
|
Collapsed=0
|
||||||
DockId=0x0000000D,0
|
DockId=0x0000001B,0
|
||||||
|
|
||||||
[Window][Lua Text Editor]
|
[Window][Lua Text Editor]
|
||||||
Pos=8,481
|
Pos=8,481
|
||||||
@ -62,20 +62,101 @@ Size=1202,569
|
|||||||
Collapsed=0
|
Collapsed=0
|
||||||
DockId=0x0000000E,0
|
DockId=0x0000000E,0
|
||||||
|
|
||||||
|
[Window][DockSpace##Dockspace]
|
||||||
|
Size=1920,1177
|
||||||
|
Collapsed=0
|
||||||
|
|
||||||
|
[Window][Inspector##InspectorWindow]
|
||||||
|
Pos=1567,27
|
||||||
|
Size=345,1142
|
||||||
|
Collapsed=0
|
||||||
|
DockId=0x00000016,0
|
||||||
|
|
||||||
|
[Window][Editor##EditorWindow]
|
||||||
|
Pos=275,27
|
||||||
|
Size=738,626
|
||||||
|
Collapsed=0
|
||||||
|
DockId=0x0000001B,0
|
||||||
|
|
||||||
|
[Window][Performance##performance]
|
||||||
|
Pos=8,720
|
||||||
|
Size=265,449
|
||||||
|
Collapsed=0
|
||||||
|
DockId=0x00000014,0
|
||||||
|
|
||||||
|
[Window][Logger##logger]
|
||||||
|
Pos=805,655
|
||||||
|
Size=760,514
|
||||||
|
Collapsed=0
|
||||||
|
DockId=0x0000001E,0
|
||||||
|
|
||||||
|
[Window][Lua Text Editor##LuaEditor]
|
||||||
|
Pos=1015,27
|
||||||
|
Size=550,626
|
||||||
|
Collapsed=0
|
||||||
|
DockId=0x0000001C,0
|
||||||
|
|
||||||
|
[Window][Scene Window@SceneWindow]
|
||||||
|
Pos=8,27
|
||||||
|
Size=301,722
|
||||||
|
Collapsed=0
|
||||||
|
DockId=0x0000000F,0
|
||||||
|
|
||||||
|
[Window][Scene Window##SceneWindow]
|
||||||
|
Pos=8,27
|
||||||
|
Size=265,691
|
||||||
|
Collapsed=0
|
||||||
|
DockId=0x00000013,0
|
||||||
|
|
||||||
|
[Window][Game Objects]
|
||||||
|
Pos=182,27
|
||||||
|
Size=301,571
|
||||||
|
Collapsed=0
|
||||||
|
DockId=0x0000001A,0
|
||||||
|
|
||||||
|
[Window][Profiler]
|
||||||
|
Pos=275,655
|
||||||
|
Size=528,514
|
||||||
|
Collapsed=0
|
||||||
|
DockId=0x0000001D,0
|
||||||
|
|
||||||
|
[Table][0xE9E836E4,4]
|
||||||
|
Column 0 Weight=1.0000
|
||||||
|
Column 1 Weight=1.0000
|
||||||
|
Column 2 Weight=1.0000
|
||||||
|
Column 3 Weight=1.0000
|
||||||
|
|
||||||
[Docking][Data]
|
[Docking][Data]
|
||||||
DockSpace ID=0x14621557 Window=0x3DA2F1DE Pos=8,27 Size=1904,1142 Split=X Selected=0xF7365A5A
|
DockSpace ID=0x14621557 Window=0x3DA2F1DE Pos=8,27 Size=1904,1142 Split=X Selected=0xF7365A5A
|
||||||
DockNode ID=0x00000009 Parent=0x14621557 SizeRef=364,1142 Split=Y Selected=0x3DC5AC3F
|
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 Selected=0x1D5D92B6
|
||||||
|
DockNode ID=0x00000014 Parent=0x00000019 SizeRef=326,449 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=0x00000005 Parent=0x00000009 SizeRef=364,745 Split=Y Selected=0x3DC5AC3F
|
||||||
DockNode ID=0x0000000B Parent=0x00000005 SizeRef=364,452 HiddenTabBar=1 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=0x0000000C Parent=0x00000005 SizeRef=364,291 Selected=0xAE3C694A
|
||||||
DockNode ID=0x00000006 Parent=0x00000009 SizeRef=364,395 HiddenTabBar=1 Selected=0x726D8899
|
DockNode ID=0x00000006 Parent=0x00000009 SizeRef=364,395 HiddenTabBar=1 Selected=0x726D8899
|
||||||
DockNode ID=0x0000000A Parent=0x14621557 SizeRef=1538,1142 Split=X
|
DockNode ID=0x0000000A Parent=0x00000012 SizeRef=1538,1142 Split=X
|
||||||
DockNode ID=0x00000007 Parent=0x0000000A SizeRef=357,1142 Selected=0x7737E8B2
|
DockNode ID=0x00000007 Parent=0x0000000A SizeRef=357,1142 Selected=0x7737E8B2
|
||||||
DockNode ID=0x00000008 Parent=0x0000000A SizeRef=1545,1142 Split=X
|
DockNode ID=0x00000008 Parent=0x0000000A SizeRef=1545,1142 Split=X
|
||||||
DockNode ID=0x00000001 Parent=0x00000008 SizeRef=1202,1142 Split=Y Selected=0xDF0EC458
|
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=0x00000003 Parent=0x00000001 SizeRef=1202,849 Split=Y Selected=0xDF0EC458
|
||||||
DockNode ID=0x0000000D Parent=0x00000003 SizeRef=1202,571 CentralNode=1 Selected=0xDF0EC458
|
DockNode ID=0x0000000D Parent=0x00000003 SizeRef=1202,571 Split=Y Selected=0xDFF75B3F
|
||||||
|
DockNode ID=0x00000017 Parent=0x0000000D SizeRef=1303,626 Split=X Selected=0xDFF75B3F
|
||||||
|
DockNode ID=0x0000001B Parent=0x00000017 SizeRef=738,626 CentralNode=1 Selected=0xDFF75B3F
|
||||||
|
DockNode ID=0x0000001C Parent=0x00000017 SizeRef=550,626 Selected=0x7D9E6BA2
|
||||||
|
DockNode ID=0x00000018 Parent=0x0000000D SizeRef=1303,514 Split=X Selected=0x9B5D3198
|
||||||
|
DockNode ID=0x0000001D Parent=0x00000018 SizeRef=528,325 Selected=0x9B5D3198
|
||||||
|
DockNode ID=0x0000001E Parent=0x00000018 SizeRef=760,325 Selected=0x1C0788A1
|
||||||
DockNode ID=0x0000000E Parent=0x00000003 SizeRef=1202,569 Selected=0xE98146C5
|
DockNode ID=0x0000000E Parent=0x00000003 SizeRef=1202,569 Selected=0xE98146C5
|
||||||
DockNode ID=0x00000004 Parent=0x00000001 SizeRef=1202,291 Selected=0x9DD4E196
|
DockNode ID=0x00000004 Parent=0x00000001 SizeRef=1202,291 Selected=0x9DD4E196
|
||||||
DockNode ID=0x00000002 Parent=0x00000008 SizeRef=334,1142 HiddenTabBar=1 Selected=0x36DC96AB
|
DockNode ID=0x00000002 Parent=0x00000008 SizeRef=334,1142 HiddenTabBar=1 Selected=0x36DC96AB
|
||||||
|
DockNode ID=0x00000016 Parent=0x14621557 SizeRef=345,1142 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
|
||||||
|
|
||||||
|
@ -2,111 +2,113 @@ Entities:
|
|||||||
- ID: 0
|
- ID: 0
|
||||||
Name: Player
|
Name: Player
|
||||||
Components:
|
Components:
|
||||||
Transform:
|
|
||||||
Position: [0, 2.79999995, -12.6000004]
|
|
||||||
Rotation: [128.988251, 128.988251, 128.988251]
|
|
||||||
Scale: [1, 1, 1]
|
|
||||||
Mesh:
|
Mesh:
|
||||||
vao: 2
|
vao: 2
|
||||||
indexCount: 15810
|
indexCount: 15810
|
||||||
textureID: 1
|
textureID: 1
|
||||||
MeshPath: assets/models/LowPolyFiatUNO.obj
|
MeshPath: assets/models/LowPolyFiatUNO.obj
|
||||||
|
Transform:
|
||||||
|
Position: [0, 2.79999995, -12.6000004]
|
||||||
|
Rotation: [466.191284, 466.191284, 466.191284]
|
||||||
|
Scale: [1, 1, 1]
|
||||||
- ID: 2
|
- ID: 2
|
||||||
Name: Gun
|
Name: Gun
|
||||||
Components:
|
Components:
|
||||||
Transform:
|
ScriptComponent:
|
||||||
Position: [-0.899999976, 0.600000024, -0.300000012]
|
ScriptPath: assets/scripts/BouncingItem.lua
|
||||||
Rotation: [203.563934, 203.563934, 203.563934]
|
|
||||||
Scale: [0.00999999978, 0.00999999978, 0.00999999978]
|
|
||||||
Mesh:
|
Mesh:
|
||||||
vao: 5
|
vao: 5
|
||||||
indexCount: 116445
|
indexCount: 116445
|
||||||
textureID: 6
|
textureID: 6
|
||||||
MeshPath: assets/models/Ak-47.obj
|
MeshPath: assets/models/Ak-47.obj
|
||||||
|
Transform:
|
||||||
|
Position: [-0.899999976, 0.727798522, -0.300000012]
|
||||||
|
Rotation: [-180, 321.793457, 0]
|
||||||
|
Scale: [0.00499999989, 0.00499999989, 0.00499999989]
|
||||||
- ID: 3
|
- ID: 3
|
||||||
Name: Grass Box Top
|
Name: Grass Box Top
|
||||||
Components:
|
Components:
|
||||||
|
Mesh:
|
||||||
|
vao: 1
|
||||||
|
indexCount: 36
|
||||||
|
textureID: 4
|
||||||
|
MeshPath: assets/models/DefaultMesh.obj
|
||||||
Transform:
|
Transform:
|
||||||
Position: [-1.20000005, -3.4000001, -17.7000008]
|
Position: [-1.20000005, -3.4000001, -17.7000008]
|
||||||
Rotation: [-23.5, 15.8999996, -59.9000015]
|
Rotation: [-23.5, 15.8999996, -59.9000015]
|
||||||
Scale: [1, 1, 1]
|
Scale: [1, 1, 1]
|
||||||
Mesh:
|
|
||||||
vao: 6
|
|
||||||
indexCount: 36
|
|
||||||
textureID: 4
|
|
||||||
MeshPath: assets/models/DefaultMesh.obj
|
|
||||||
- ID: 4
|
- ID: 4
|
||||||
Name: Bark Box
|
Name: Bark Box
|
||||||
Components:
|
Components:
|
||||||
|
Mesh:
|
||||||
|
vao: 1
|
||||||
|
indexCount: 36
|
||||||
|
textureID: 5
|
||||||
|
MeshPath: assets/models/DefaultMesh.obj
|
||||||
Transform:
|
Transform:
|
||||||
Position: [8.10000038, 0.800000012, -12]
|
Position: [8.10000038, 0.800000012, -12]
|
||||||
Rotation: [-17.2999992, -16.1000004, -19.2999992]
|
Rotation: [-17.2999992, -16.1000004, -19.2999992]
|
||||||
Scale: [1, 1, 1]
|
Scale: [1, 1, 1]
|
||||||
Mesh:
|
|
||||||
vao: 6
|
|
||||||
indexCount: 36
|
|
||||||
textureID: 5
|
|
||||||
MeshPath: assets/models/DefaultMesh.obj
|
|
||||||
- ID: 5
|
- ID: 5
|
||||||
Name: Skybox
|
Name: Skybox
|
||||||
Components:
|
Components:
|
||||||
Mesh:
|
|
||||||
vao: 6
|
|
||||||
indexCount: 36
|
|
||||||
textureID: 7
|
|
||||||
MeshPath: assets/models/DefaultMesh.obj
|
|
||||||
Transform:
|
Transform:
|
||||||
Position: [0, 0, 43.2000008]
|
Position: [0, 0, 43.2000008]
|
||||||
Rotation: [0, 0, 0]
|
Rotation: [0, 0, 0]
|
||||||
Scale: [100, 100, 100]
|
Scale: [100, 100, 100]
|
||||||
|
Mesh:
|
||||||
|
vao: 1
|
||||||
|
indexCount: 36
|
||||||
|
textureID: 7
|
||||||
|
MeshPath: assets/models/DefaultMesh.obj
|
||||||
- ID: 6
|
- ID: 6
|
||||||
Name: Null Texture Box
|
Name: Null Texture Box
|
||||||
Components:
|
Components:
|
||||||
|
Mesh:
|
||||||
|
vao: 1
|
||||||
|
indexCount: 36
|
||||||
|
textureID: 3
|
||||||
|
MeshPath: assets/models/DefaultMesh.obj
|
||||||
Transform:
|
Transform:
|
||||||
Position: [-6.5, -6, -18]
|
Position: [-6.5, -6, -18]
|
||||||
Rotation: [15.8000002, -18.2000008, -11.1000004]
|
Rotation: [15.8000002, -18.2000008, -11.1000004]
|
||||||
Scale: [1, 1, 1]
|
Scale: [1, 1, 1]
|
||||||
Mesh:
|
|
||||||
vao: 6
|
|
||||||
indexCount: 36
|
|
||||||
textureID: 3
|
|
||||||
MeshPath: assets/models/DefaultMesh.obj
|
|
||||||
- ID: 7
|
- ID: 7
|
||||||
Name: Grass Box Bottom
|
Name: Grass Box Bottom
|
||||||
Components:
|
Components:
|
||||||
|
Mesh:
|
||||||
|
vao: 1
|
||||||
|
indexCount: 36
|
||||||
|
textureID: 4
|
||||||
|
MeshPath: assets/models/DefaultMesh.obj
|
||||||
Transform:
|
Transform:
|
||||||
Position: [6.5999999, 1.79999995, -23.8999996]
|
Position: [6.5999999, 1.79999995, -23.8999996]
|
||||||
Rotation: [-16.1000004, -15.8999996, -35]
|
Rotation: [-16.1000004, -15.8999996, -35]
|
||||||
Scale: [1, 1, 1]
|
Scale: [1, 1, 1]
|
||||||
Mesh:
|
|
||||||
vao: 6
|
|
||||||
indexCount: 36
|
|
||||||
textureID: 4
|
|
||||||
MeshPath: assets/models/DefaultMesh.obj
|
|
||||||
- ID: 8
|
- ID: 8
|
||||||
Name: Wood Box
|
Name: Wood Box
|
||||||
Components:
|
Components:
|
||||||
|
Mesh:
|
||||||
|
vao: 1
|
||||||
|
indexCount: 36
|
||||||
|
textureID: 1
|
||||||
|
MeshPath: assets/models/DefaultMesh.obj
|
||||||
Transform:
|
Transform:
|
||||||
Position: [-7.80000019, 0.200000003, -29.7999992]
|
Position: [-7.80000019, 0.200000003, -29.7999992]
|
||||||
Rotation: [22.2999992, -32.7999992, 0]
|
Rotation: [22.2999992, -32.7999992, 0]
|
||||||
Scale: [1, 1, 1]
|
Scale: [1, 1, 1]
|
||||||
Mesh:
|
|
||||||
vao: 6
|
|
||||||
indexCount: 36
|
|
||||||
textureID: 1
|
|
||||||
MeshPath: assets/models/DefaultMesh.obj
|
|
||||||
- ID: 9
|
- ID: 9
|
||||||
Name: Bricks
|
Name: Bricks
|
||||||
Components:
|
Components:
|
||||||
|
Mesh:
|
||||||
|
vao: 1
|
||||||
|
indexCount: 36
|
||||||
|
textureID: 2
|
||||||
|
MeshPath: assets/models/DefaultMesh.obj
|
||||||
Transform:
|
Transform:
|
||||||
Position: [5.5, -2.9000001, -19.5]
|
Position: [5.5, -2.9000001, -19.5]
|
||||||
Rotation: [-41.4000015, -22.6000004, -52.2999992]
|
Rotation: [-41.4000015, -22.6000004, -52.2999992]
|
||||||
Scale: [1, 1, 1]
|
Scale: [1, 1, 1]
|
||||||
Mesh:
|
|
||||||
vao: 6
|
|
||||||
indexCount: 36
|
|
||||||
textureID: 2
|
|
||||||
MeshPath: assets/models/DefaultMesh.obj
|
|
||||||
- ID: 10
|
- ID: 10
|
||||||
Name: Script Handler
|
Name: Script Handler
|
||||||
Components:
|
Components:
|
||||||
|
172
src/Componenets/CameraComponent.cpp
Normal file
172
src/Componenets/CameraComponent.cpp
Normal file
@ -0,0 +1,172 @@
|
|||||||
|
// CameraComponent.cpp
|
||||||
|
|
||||||
|
#include "CameraComponent.h"
|
||||||
|
#include "GameObject.h" // Ensure this is included to access GameObject
|
||||||
|
#include "Transform.h" // Ensure Transform component is available
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
// 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)
|
||||||
|
{
|
||||||
|
UpdateProjectionMatrix();
|
||||||
|
}
|
||||||
|
|
||||||
|
CameraComponent::~CameraComponent()
|
||||||
|
{
|
||||||
|
// Cleanup if necessary
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::string &CameraComponent::GetName() const
|
||||||
|
{
|
||||||
|
static const std::string name = "CameraComponent";
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::string &CameraComponent::GetStaticName()
|
||||||
|
{
|
||||||
|
static const std::string name = "CameraComponent";
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
YAML::Node CameraComponent::Serialize()
|
||||||
|
{
|
||||||
|
YAML::Node node;
|
||||||
|
node["IsPerspective"] = m_IsPerspective;
|
||||||
|
if (m_IsPerspective)
|
||||||
|
{
|
||||||
|
node["FOV"] = m_FOV;
|
||||||
|
node["AspectRatio"] = m_AspectRatio;
|
||||||
|
node["NearPlane"] = m_NearPlane;
|
||||||
|
node["FarPlane"] = m_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;
|
||||||
|
}
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CameraComponent::Deserialize(const YAML::Node &node)
|
||||||
|
{
|
||||||
|
if (node["IsPerspective"])
|
||||||
|
{
|
||||||
|
m_IsPerspective = node["IsPerspective"].as<bool>();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_IsPerspective)
|
||||||
|
{
|
||||||
|
if (node["FOV"])
|
||||||
|
m_FOV = node["FOV"].as<float>();
|
||||||
|
if (node["AspectRatio"])
|
||||||
|
m_AspectRatio = node["AspectRatio"].as<float>();
|
||||||
|
if (node["NearPlane"])
|
||||||
|
m_NearPlane = node["NearPlane"].as<float>();
|
||||||
|
if (node["FarPlane"])
|
||||||
|
m_FarPlane = node["FarPlane"].as<float>();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (node["Left"])
|
||||||
|
m_Left = node["Left"].as<float>();
|
||||||
|
if (node["Right"])
|
||||||
|
m_Right = node["Right"].as<float>();
|
||||||
|
if (node["Bottom"])
|
||||||
|
m_Bottom = node["Bottom"].as<float>();
|
||||||
|
if (node["Top"])
|
||||||
|
m_Top = node["Top"].as<float>();
|
||||||
|
if (node["NearPlane"])
|
||||||
|
m_NearPlane = node["NearPlane"].as<float>();
|
||||||
|
if (node["FarPlane"])
|
||||||
|
m_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;
|
||||||
|
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;
|
||||||
|
UpdateProjectionMatrix();
|
||||||
|
}
|
||||||
|
|
||||||
|
const glm::mat4 &CameraComponent::GetViewMatrix() const
|
||||||
|
{
|
||||||
|
return m_ViewMatrix;
|
||||||
|
}
|
||||||
|
|
||||||
|
const glm::mat4 &CameraComponent::GetProjectionMatrix() const
|
||||||
|
{
|
||||||
|
return m_ProjectionMatrix;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CameraComponent::UpdateViewMatrix()
|
||||||
|
{
|
||||||
|
// Retrieve the Transform component from the owning GameObject
|
||||||
|
std::shared_ptr<TransformComponent> transform = owner->GetComponent<TransformComponent>();
|
||||||
|
|
||||||
|
if (transform)
|
||||||
|
{
|
||||||
|
glm::vec3 position = transform->GetPosition();
|
||||||
|
glm::vec3 rotation = transform->GetRotation();
|
||||||
|
|
||||||
|
// Convert Euler angles to radians
|
||||||
|
glm::vec3 rotRad = glm::radians(rotation);
|
||||||
|
|
||||||
|
// 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
|
||||||
|
{
|
||||||
|
std::cerr << "Transform component missing on GameObject: " << m_Owner->name << std::endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CameraComponent::UpdateProjectionMatrix()
|
||||||
|
{
|
||||||
|
if (m_IsPerspective)
|
||||||
|
{
|
||||||
|
m_ProjectionMatrix = glm::perspective(glm::radians(m_FOV), m_AspectRatio, m_NearPlane, m_FarPlane);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
m_ProjectionMatrix = glm::ortho(m_Left, m_Right, m_Bottom, m_Top, m_NearPlane, m_FarPlane);
|
||||||
|
}
|
||||||
|
}
|
56
src/Componenets/CameraComponent.h
Normal file
56
src/Componenets/CameraComponent.h
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
// CameraComponent.h
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "Component.h"
|
||||||
|
#include "GameObject.h"
|
||||||
|
#include <glm/glm.hpp>
|
||||||
|
#include <glm/gtc/matrix_transform.hpp>
|
||||||
|
#include <yaml-cpp/yaml.h>
|
||||||
|
|
||||||
|
class CameraComponent : public Component
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
// Updated constructor to accept GameObject*
|
||||||
|
CameraComponent();
|
||||||
|
virtual ~CameraComponent();
|
||||||
|
|
||||||
|
// Overridden methods from Component
|
||||||
|
virtual const std::string& GetName() const override;
|
||||||
|
|
||||||
|
static const std::string& GetStaticName();
|
||||||
|
|
||||||
|
virtual YAML::Node Serialize() 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;
|
||||||
|
|
||||||
|
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();
|
||||||
|
};
|
@ -1,16 +1,38 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
// Component.h
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <yaml-cpp/yaml.h>
|
#include <yaml-cpp/yaml.h>
|
||||||
|
|
||||||
|
// Forward declaration to avoid circular dependency
|
||||||
|
class GameObject;
|
||||||
|
|
||||||
class Component
|
class Component
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
// Constructor accepting a pointer to the owning GameObject
|
||||||
|
Component() {}
|
||||||
|
|
||||||
|
// Virtual destructor
|
||||||
virtual ~Component() {}
|
virtual ~Component() {}
|
||||||
|
|
||||||
|
// Pure virtual methods
|
||||||
virtual const std::string& GetName() const = 0;
|
virtual const std::string& GetName() const = 0;
|
||||||
|
|
||||||
|
void SetOwner(GameObject* owner) {
|
||||||
|
|
||||||
|
m_Owner = owner;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
// Serialization methods
|
// Serialization methods
|
||||||
virtual YAML::Node Serialize() = 0;
|
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; }
|
||||||
|
|
||||||
|
protected:
|
||||||
|
GameObject* m_Owner; // Pointer to the owning GameObject
|
||||||
};
|
};
|
@ -27,6 +27,7 @@ std::string GameObject::GetName() const
|
|||||||
|
|
||||||
void GameObject::AddComponent(const std::shared_ptr<Component> &component)
|
void GameObject::AddComponent(const std::shared_ptr<Component> &component)
|
||||||
{
|
{
|
||||||
|
component->SetOwner(this);
|
||||||
components[component->GetName()] = component;
|
components[component->GetName()] = component;
|
||||||
// std::cout << "Added " << component->GetName() << std::endl;
|
// std::cout << "Added " << component->GetName() << std::endl;
|
||||||
}
|
}
|
||||||
|
@ -14,8 +14,9 @@ const std::string ScriptComponent::name = "ScriptComponent";
|
|||||||
|
|
||||||
|
|
||||||
ScriptComponent::ScriptComponent()
|
ScriptComponent::ScriptComponent()
|
||||||
: ScriptPath(""), m_LastErrorMessage("")
|
: ScriptPath("assets/scripts/script.lua"), m_LastErrorMessage("")
|
||||||
{
|
{
|
||||||
|
|
||||||
Initialize();
|
Initialize();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -22,6 +22,9 @@
|
|||||||
#include "Windows/InspectorWindow.h"
|
#include "Windows/InspectorWindow.h"
|
||||||
#include "Windows/SceneWindow.h"
|
#include "Windows/SceneWindow.h"
|
||||||
|
|
||||||
|
#include "Windows/ProfilerWindow.h"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// Create an instance
|
// Create an instance
|
||||||
|
|
||||||
@ -30,6 +33,10 @@
|
|||||||
#include "Engine/ThemeManager.h"
|
#include "Engine/ThemeManager.h"
|
||||||
#include "Engine/SceneManager.h"
|
#include "Engine/SceneManager.h"
|
||||||
#include "Engine/LuaAPI.h"
|
#include "Engine/LuaAPI.h"
|
||||||
|
#include "Engine/Utilitys.h"
|
||||||
|
|
||||||
|
#include "Engine/ScopedTimer.h"
|
||||||
|
#include "Engine/Profiler.h"
|
||||||
|
|
||||||
// #define YAML_CPP_STATIC_DEFINE
|
// #define YAML_CPP_STATIC_DEFINE
|
||||||
#include <yaml-cpp/yaml.h>
|
#include <yaml-cpp/yaml.h>
|
||||||
@ -42,16 +49,13 @@ LoggerWindow *g_LoggerWindow;
|
|||||||
|
|
||||||
SceneManager g_SceneManager;
|
SceneManager g_SceneManager;
|
||||||
|
|
||||||
|
|
||||||
std::vector<std::shared_ptr<GameObject>> g_GameObjects;
|
std::vector<std::shared_ptr<GameObject>> g_GameObjects;
|
||||||
|
|
||||||
int g_GPU_Triangles_drawn_to_screen = 0;
|
int g_GPU_Triangles_drawn_to_screen = 0;
|
||||||
|
|
||||||
GameObject *g_SelectedObject; // Pointer to the currently selected object
|
GameObject *g_SelectedObject; // Pointer to the currently selected object
|
||||||
|
|
||||||
|
int m_GameRunning = 0;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
bool MyEngine::Init(int width, int height, const std::string &title)
|
bool MyEngine::Init(int width, int height, const std::string &title)
|
||||||
{
|
{
|
||||||
@ -116,7 +120,10 @@ bool MyEngine::Init(int width, int height, const std::string &title)
|
|||||||
m_InspectorWindow = std::make_unique<InspectorWindow>();
|
m_InspectorWindow = std::make_unique<InspectorWindow>();
|
||||||
m_SceneWindow = std::make_unique<SceneWindow>();
|
m_SceneWindow = std::make_unique<SceneWindow>();
|
||||||
m_luaEditor = std::make_unique<LuaEditorWindow>();
|
m_luaEditor = std::make_unique<LuaEditorWindow>();
|
||||||
|
m_profilerWindow = std::make_unique<ProfilerWindow>();
|
||||||
|
|
||||||
|
m_GameRunning = false;
|
||||||
|
m_FirstTickGameRunning = true;
|
||||||
|
|
||||||
g_LoggerWindow = m_LoggerWindow.get();
|
g_LoggerWindow = m_LoggerWindow.get();
|
||||||
|
|
||||||
@ -160,7 +167,7 @@ void MyEngine::Run()
|
|||||||
if (mesh)
|
if (mesh)
|
||||||
{
|
{
|
||||||
// printf("Got Valid Mesh Component\n");
|
// printf("Got Valid Mesh Component\n");
|
||||||
Model * model = g_AssetManager.loadAsset<Model *>(AssetType::MODEL, "assets/models/DefaultCube.obj");
|
Model *model = g_AssetManager.loadAsset<Model *>(AssetType::MODEL, "assets/models/DefaultMesh.obj");
|
||||||
mesh->vao = model->vao;
|
mesh->vao = model->vao;
|
||||||
mesh->indexCount = model->indices.size();
|
mesh->indexCount = model->indices.size();
|
||||||
mesh->textureID = g_AssetManager.loadAsset<GLuint>(AssetType::TEXTURE, "assets/textures/wood.png");
|
mesh->textureID = g_AssetManager.loadAsset<GLuint>(AssetType::TEXTURE, "assets/textures/wood.png");
|
||||||
@ -190,7 +197,6 @@ void MyEngine::Run()
|
|||||||
g_AssetManager.loadAsset<GLuint>(AssetType::TEXTURE, "assets/textures/vegetation_tree_bark_40.png");
|
g_AssetManager.loadAsset<GLuint>(AssetType::TEXTURE, "assets/textures/vegetation_tree_bark_40.png");
|
||||||
g_AssetManager.loadAsset<GLuint>(AssetType::TEXTURE, "assets/textures/ak-47.jpg");
|
g_AssetManager.loadAsset<GLuint>(AssetType::TEXTURE, "assets/textures/ak-47.jpg");
|
||||||
|
|
||||||
|
|
||||||
g_AssetManager.loadAsset<GLuint>(AssetType::TEXTURE, "assets/textures/sky.png");
|
g_AssetManager.loadAsset<GLuint>(AssetType::TEXTURE, "assets/textures/sky.png");
|
||||||
|
|
||||||
// Load a model
|
// Load a model
|
||||||
@ -223,8 +229,13 @@ void MyEngine::Run()
|
|||||||
|
|
||||||
while (!glfwWindowShouldClose(m_Window) && m_Running)
|
while (!glfwWindowShouldClose(m_Window) && m_Running)
|
||||||
{
|
{
|
||||||
|
ScopedTimer frameTimer("MainLoop"); // Optional: Profile the entire loop
|
||||||
|
|
||||||
// Poll events
|
// Poll events
|
||||||
|
{
|
||||||
|
ScopedTimer timer("glfwPollEvents");
|
||||||
glfwPollEvents();
|
glfwPollEvents();
|
||||||
|
}
|
||||||
|
|
||||||
// Calculate current time
|
// Calculate current time
|
||||||
double current_time = glfwGetTime();
|
double current_time = glfwGetTime();
|
||||||
@ -251,43 +262,75 @@ void MyEngine::Run()
|
|||||||
// Start new frame
|
// Start new frame
|
||||||
BeginFrame();
|
BeginFrame();
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!m_FirstTickGameRunning && !m_GameRunning)
|
||||||
|
{
|
||||||
|
ScopedTimer timer("LoadScene");
|
||||||
|
m_FirstTickGameRunning = true;
|
||||||
|
|
||||||
|
std::string loadPath = createTempFolder().string() + "TesseractEngineTempScene.scene";
|
||||||
|
|
||||||
|
DEBUG_PRINT("Load path: %s", loadPath.c_str());
|
||||||
|
|
||||||
|
g_SceneManager.LoadScene(g_GameObjects, loadPath);
|
||||||
|
}
|
||||||
|
|
||||||
// Show main DockSpace
|
// Show main DockSpace
|
||||||
ShowDockSpace();
|
ShowDockSpace();
|
||||||
|
|
||||||
m_InspectorWindow->Show();
|
if (m_GameRunning)
|
||||||
|
|
||||||
if (1)
|
|
||||||
{
|
{
|
||||||
|
ScopedTimer timer("UpdateGameObjects");
|
||||||
for (auto &Gameobject : g_GameObjects)
|
for (auto &Gameobject : g_GameObjects)
|
||||||
{
|
{
|
||||||
|
|
||||||
// Handle Componenets That require Updates
|
// Handle Components That Require Updates
|
||||||
|
|
||||||
std::shared_ptr<ScriptComponent> script = Gameobject->GetComponent<ScriptComponent>();
|
std::shared_ptr<ScriptComponent> script = Gameobject->GetComponent<ScriptComponent>();
|
||||||
if (script)
|
if (script)
|
||||||
{ // Stupid Null Checks
|
{ // Null Checks
|
||||||
|
ScopedTimer timer("GameObjectLuaCall: "+Gameobject->name);
|
||||||
|
|
||||||
script->Update(frame_delta);
|
script->Update(frame_delta);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Pass per-frame delta time to Lua
|
// Render and show various windows
|
||||||
|
{
|
||||||
|
ScopedTimer timer("RenderGame");
|
||||||
|
|
||||||
m_RenderWindow->Show(); // The spinning triangle as ImGui::Image
|
m_RenderWindow->Show(&m_GameRunning); // The spinning triangle as ImGui::Image
|
||||||
|
|
||||||
|
}
|
||||||
|
{
|
||||||
|
ScopedTimer timer("ShowEditor");
|
||||||
|
|
||||||
|
m_InspectorWindow->Show();
|
||||||
m_PerformanceWindow->Show(m_Fps, m_Ms); // FPS & ms
|
m_PerformanceWindow->Show(m_Fps, m_Ms); // FPS & ms
|
||||||
|
|
||||||
m_LoggerWindow->Show(); // Logs
|
m_LoggerWindow->Show(); // Logs
|
||||||
|
|
||||||
m_SceneWindow->Show();
|
m_SceneWindow->Show();
|
||||||
|
|
||||||
m_luaEditor->Show();
|
m_luaEditor->Show();
|
||||||
|
|
||||||
|
m_profilerWindow->Show();
|
||||||
|
}
|
||||||
|
|
||||||
// After rendering
|
// After rendering
|
||||||
m_PerformanceWindow->UpdatePerformanceStats(-1, g_GPU_Triangles_drawn_to_screen);
|
m_PerformanceWindow->UpdatePerformanceStats(-1, g_GPU_Triangles_drawn_to_screen);
|
||||||
|
|
||||||
// End frame
|
// End frame
|
||||||
EndFrame();
|
EndFrame();
|
||||||
|
|
||||||
|
// Mark the end of frame for profiling
|
||||||
|
Profiler::Get().EndFrame();
|
||||||
}
|
}
|
||||||
|
|
||||||
DEBUG_PRINT("[OK] Engine Run ");
|
DEBUG_PRINT("[OK] Engine Run ");
|
||||||
@ -398,6 +441,17 @@ void MyEngine::ShowDockSpace()
|
|||||||
}
|
}
|
||||||
ImGui::EndMenu();
|
ImGui::EndMenu();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (ImGui::BeginMenu("Engine"))
|
||||||
|
{
|
||||||
|
|
||||||
|
if (ImGui::MenuItem(m_GameRunning ? "Stop" : "Start"))
|
||||||
|
{
|
||||||
|
m_GameRunning = !m_GameRunning; // Stop the engine
|
||||||
|
}
|
||||||
|
ImGui::EndMenu();
|
||||||
|
}
|
||||||
|
|
||||||
ImGui::EndMenuBar();
|
ImGui::EndMenuBar();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
// src/Engine.h
|
// src/Engine.h
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include "Windows/RenderWindow.h"
|
#include "Windows/RenderWindow.h"
|
||||||
@ -9,6 +10,7 @@
|
|||||||
#include "Windows/InspectorWindow.h"
|
#include "Windows/InspectorWindow.h"
|
||||||
#include "Windows/SceneWindow.h"
|
#include "Windows/SceneWindow.h"
|
||||||
#include "Windows/LuaEditorWindow.h"
|
#include "Windows/LuaEditorWindow.h"
|
||||||
|
#include "Windows/ProfilerWindow.h"
|
||||||
|
|
||||||
#include "Componenets/GameObject.h"
|
#include "Componenets/GameObject.h"
|
||||||
#include "Componenets/Mesh.h"
|
#include "Componenets/Mesh.h"
|
||||||
@ -18,6 +20,7 @@
|
|||||||
#include "Engine/ThemeManager.h"
|
#include "Engine/ThemeManager.h"
|
||||||
#include "Engine/SceneManager.h"
|
#include "Engine/SceneManager.h"
|
||||||
#include "Engine/LuaAPI.h"
|
#include "Engine/LuaAPI.h"
|
||||||
|
#include "Engine/Utilitys.h"
|
||||||
|
|
||||||
#include "TestModel.h"
|
#include "TestModel.h"
|
||||||
|
|
||||||
@ -43,6 +46,9 @@ private:
|
|||||||
private:
|
private:
|
||||||
GLFWwindow *m_Window = nullptr;
|
GLFWwindow *m_Window = nullptr;
|
||||||
bool m_Running = false;
|
bool m_Running = false;
|
||||||
|
bool m_GameRunning = false;
|
||||||
|
|
||||||
|
bool m_FirstTickGameRunning = true;
|
||||||
|
|
||||||
// Windows
|
// Windows
|
||||||
std::unique_ptr<RenderWindow> m_RenderWindow;
|
std::unique_ptr<RenderWindow> m_RenderWindow;
|
||||||
@ -52,6 +58,8 @@ private:
|
|||||||
std::unique_ptr<SceneWindow> m_SceneWindow;
|
std::unique_ptr<SceneWindow> m_SceneWindow;
|
||||||
std::unique_ptr<LuaEditorWindow> m_luaEditor;
|
std::unique_ptr<LuaEditorWindow> m_luaEditor;
|
||||||
|
|
||||||
|
std::unique_ptr<ProfilerWindow> m_profilerWindow;
|
||||||
|
|
||||||
double m_LastFrameTime = 0.0; // Initialize with the current time
|
double m_LastFrameTime = 0.0; // Initialize with the current time
|
||||||
double m_TimeAccumulator = 0.0;
|
double m_TimeAccumulator = 0.0;
|
||||||
|
|
||||||
|
@ -56,13 +56,6 @@ public:
|
|||||||
|
|
||||||
using AssetVariant = std::variant<GLuint, Shader *, std::string, Model *>;
|
using AssetVariant = std::variant<GLuint, Shader *, std::string, Model *>;
|
||||||
|
|
||||||
// Load an asset from disk (texture, shader, etc.)
|
|
||||||
// Returns a void* pointer to the loaded resource.
|
|
||||||
// - For TEXTURE, cast to (GLuint)
|
|
||||||
// - For SHADER, cast to (Shader*)
|
|
||||||
// - For SOUND, cast to whatever you store
|
|
||||||
|
|
||||||
// Template function to load an asset
|
|
||||||
// Template function to load an asset
|
// Template function to load an asset
|
||||||
template <typename T>
|
template <typename T>
|
||||||
T loadAsset(AssetType type, const std::string &path)
|
T loadAsset(AssetType type, const std::string &path)
|
||||||
|
@ -142,6 +142,7 @@ bool LuaManager::Initialize(const std::string &scriptPath)
|
|||||||
// Update function called every frame
|
// Update function called every frame
|
||||||
void LuaManager::Update(float deltaTime)
|
void LuaManager::Update(float deltaTime)
|
||||||
{
|
{
|
||||||
|
|
||||||
if (!m_LuaState)
|
if (!m_LuaState)
|
||||||
{
|
{
|
||||||
if (g_LoggerWindow)
|
if (g_LoggerWindow)
|
||||||
|
47
src/Engine/Profiler.h
Normal file
47
src/Engine/Profiler.h
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
// Profiler.h
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <unordered_map>
|
||||||
|
#include <mutex>
|
||||||
|
|
||||||
|
struct ProfileResult {
|
||||||
|
double TotalTime; // Total time in microseconds
|
||||||
|
int CallCount;
|
||||||
|
};
|
||||||
|
|
||||||
|
class Profiler {
|
||||||
|
public:
|
||||||
|
static Profiler& Get() {
|
||||||
|
static Profiler instance;
|
||||||
|
return instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
void AddProfileResult(const std::string& name, double time) {
|
||||||
|
std::lock_guard<std::mutex> lock(m_Mutex);
|
||||||
|
auto& result = m_ProfileData[name];
|
||||||
|
result.TotalTime += time;
|
||||||
|
result.CallCount += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Call this at the end of each frame to prepare data for display
|
||||||
|
void EndFrame() {
|
||||||
|
std::lock_guard<std::mutex> lock(m_Mutex);
|
||||||
|
m_LastFrameData = m_ProfileData;
|
||||||
|
m_ProfileData.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::unordered_map<std::string, ProfileResult>& GetLastFrameData() const {
|
||||||
|
return m_LastFrameData;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
Profiler() {}
|
||||||
|
~Profiler() {}
|
||||||
|
Profiler(const Profiler&) = delete;
|
||||||
|
Profiler& operator=(const Profiler&) = delete;
|
||||||
|
|
||||||
|
std::unordered_map<std::string, ProfileResult> m_ProfileData;
|
||||||
|
std::unordered_map<std::string, ProfileResult> m_LastFrameData;
|
||||||
|
mutable std::mutex m_Mutex;
|
||||||
|
};
|
12
src/Engine/ScopedTimer.cpp
Normal file
12
src/Engine/ScopedTimer.cpp
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
// ScopedTimer.cpp
|
||||||
|
#include "ScopedTimer.h"
|
||||||
|
#include "Profiler.h"
|
||||||
|
|
||||||
|
ScopedTimer::ScopedTimer(const std::string& name)
|
||||||
|
: m_Name(name), m_StartTime(std::chrono::high_resolution_clock::now()) {}
|
||||||
|
|
||||||
|
ScopedTimer::~ScopedTimer() {
|
||||||
|
auto endTime = std::chrono::high_resolution_clock::now();
|
||||||
|
double duration = std::chrono::duration<double, std::micro>(endTime - m_StartTime).count(); // Duration in microseconds
|
||||||
|
Profiler::Get().AddProfileResult(m_Name, duration);
|
||||||
|
}
|
17
src/Engine/ScopedTimer.h
Normal file
17
src/Engine/ScopedTimer.h
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
// ScopedTimer.h
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <chrono>
|
||||||
|
|
||||||
|
class Profiler; // Forward declaration
|
||||||
|
|
||||||
|
class ScopedTimer {
|
||||||
|
public:
|
||||||
|
ScopedTimer(const std::string& name);
|
||||||
|
~ScopedTimer();
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::string m_Name;
|
||||||
|
std::chrono::high_resolution_clock::time_point m_StartTime;
|
||||||
|
};
|
58
src/Engine/Utilitys.cpp
Normal file
58
src/Engine/Utilitys.cpp
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
#include <iostream>
|
||||||
|
#include <filesystem>
|
||||||
|
#include <string>
|
||||||
|
#include <random>
|
||||||
|
#include <chrono>
|
||||||
|
|
||||||
|
namespace fs = std::filesystem;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Creates a unique temporary folder in the user's temp directory.
|
||||||
|
*
|
||||||
|
* This function generates a unique folder name using a combination of a prefix
|
||||||
|
* and random characters. If the folder already exists, it returns the existing path.
|
||||||
|
*
|
||||||
|
* @return fs::path The path to the created or existing temporary folder.
|
||||||
|
* @throws fs::filesystem_error if directory creation fails.
|
||||||
|
*/
|
||||||
|
std::filesystem::path createTempFolder() {
|
||||||
|
const std::string folder_name = "temp_tesseract_fixed";
|
||||||
|
|
||||||
|
// Get the system's temporary directory
|
||||||
|
fs::path temp_dir = fs::temp_directory_path();
|
||||||
|
|
||||||
|
// Define the fixed folder path
|
||||||
|
fs::path fixed_folder = temp_dir / folder_name;
|
||||||
|
|
||||||
|
// Check if the folder exists
|
||||||
|
if (fs::exists(fixed_folder)) {
|
||||||
|
if (fs::is_directory(fixed_folder)) {
|
||||||
|
// Folder already exists; return its path
|
||||||
|
return fixed_folder;
|
||||||
|
} else {
|
||||||
|
// A file with the same name exists; handle the conflict
|
||||||
|
throw fs::filesystem_error("A file with the fixed folder name exists.",
|
||||||
|
fixed_folder,
|
||||||
|
std::error_code());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Attempt to create the directory
|
||||||
|
try {
|
||||||
|
if (fs::create_directory(fixed_folder)) {
|
||||||
|
// Successfully created the folder
|
||||||
|
return fixed_folder;
|
||||||
|
} else {
|
||||||
|
// Failed to create the folder for an unknown reason
|
||||||
|
throw fs::filesystem_error("Failed to create the fixed temporary folder.",
|
||||||
|
fixed_folder,
|
||||||
|
std::error_code());
|
||||||
|
}
|
||||||
|
} catch (const fs::filesystem_error& e) {
|
||||||
|
// Handle filesystem errors (e.g., permission issues)
|
||||||
|
std::cerr << "Error creating directory: " << e.what() << '\n';
|
||||||
|
throw; // Re-throw the exception after logging
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
7
src/Engine/Utilitys.h
Normal file
7
src/Engine/Utilitys.h
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
#include <filesystem>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
std::filesystem::path createTempFolder();
|
||||||
|
|
@ -18,7 +18,7 @@ void InspectorWindow::Show()
|
|||||||
ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(6, 4));
|
ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(6, 4));
|
||||||
ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(10, 10));
|
ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(10, 10));
|
||||||
|
|
||||||
if (ImGui::Begin("Inspector"))
|
if (ImGui::Begin("Inspector##InspectorWindow"))
|
||||||
{
|
{
|
||||||
// Title label (white text)
|
// Title label (white text)
|
||||||
if (g_SelectedObject)
|
if (g_SelectedObject)
|
||||||
@ -34,8 +34,6 @@ void InspectorWindow::Show()
|
|||||||
ImGui::Text("Editing Object: %s", g_SelectedObject->name.c_str());
|
ImGui::Text("Editing Object: %s", g_SelectedObject->name.c_str());
|
||||||
ImGui::Text("Components: %d", g_SelectedObject->GetComponentCount());
|
ImGui::Text("Components: %d", g_SelectedObject->GetComponentCount());
|
||||||
|
|
||||||
ImGui::Spacing();
|
|
||||||
ImGui::Separator();
|
|
||||||
ImGui::Spacing();
|
ImGui::Spacing();
|
||||||
|
|
||||||
// Begin two-column layout for labels and inputs
|
// Begin two-column layout for labels and inputs
|
||||||
@ -69,9 +67,93 @@ void InspectorWindow::Show()
|
|||||||
// End columns
|
// End columns
|
||||||
ImGui::Columns(1);
|
ImGui::Columns(1);
|
||||||
|
|
||||||
ImGui::Spacing();
|
|
||||||
ImGui::Separator();
|
ImGui::Separator();
|
||||||
ImGui::Spacing();
|
|
||||||
|
// ===========================
|
||||||
|
// 2) ADD COMPONENT SECTION
|
||||||
|
// ===========================
|
||||||
|
|
||||||
|
|
||||||
|
ImGui::Text("Add Component:");
|
||||||
|
ImGui::SameLine();
|
||||||
|
|
||||||
|
// Define available components to add
|
||||||
|
static int selectedComponent = 0;
|
||||||
|
const char *componentOptions[] = {"Transform", "Mesh", "Script", "Camera"};
|
||||||
|
const int componentCount = sizeof(componentOptions) / sizeof(componentOptions[0]);
|
||||||
|
|
||||||
|
// Create a Combo Box for component selection
|
||||||
|
|
||||||
|
ImGui::Combo("##ComponentCombo", &selectedComponent, componentOptions, componentCount);
|
||||||
|
|
||||||
|
// Add Button to add the selected component
|
||||||
|
if (ImGui::Button("Add"))
|
||||||
|
{
|
||||||
|
if (selectedComponent == 0) // TransformComponent
|
||||||
|
{
|
||||||
|
// Check if TransformComponent already exists to prevent duplicates
|
||||||
|
std::shared_ptr<TransformComponent> existingTransform = g_SelectedObject->GetComponent<TransformComponent>();
|
||||||
|
if (!existingTransform)
|
||||||
|
{
|
||||||
|
g_SelectedObject->AddComponent(std::make_shared<TransformComponent>());
|
||||||
|
g_LoggerWindow->AddLog("TransformComponent added to %s.", g_SelectedObject->name.c_str());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
g_LoggerWindow->AddLog("TransformComponent already exists on %s.", g_SelectedObject->name.c_str());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (selectedComponent == 1) // MeshComponent
|
||||||
|
{
|
||||||
|
// Check if MeshComponent already exists to prevent duplicates
|
||||||
|
std::shared_ptr<MeshComponent> existingMesh = g_SelectedObject->GetComponent<MeshComponent>();
|
||||||
|
if (!existingMesh)
|
||||||
|
{
|
||||||
|
g_SelectedObject->AddComponent(std::make_shared<MeshComponent>());
|
||||||
|
g_LoggerWindow->AddLog("MeshComponent added to %s.", g_SelectedObject->name.c_str());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
g_LoggerWindow->AddLog("MeshComponent already exists on %s.", g_SelectedObject->name.c_str());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (selectedComponent == 2) // ScriptComponent
|
||||||
|
{
|
||||||
|
// Check if ScriptComponent already exists to prevent duplicates
|
||||||
|
std::shared_ptr<ScriptComponent> existingScript = g_SelectedObject->GetComponent<ScriptComponent>();
|
||||||
|
if (!existingScript)
|
||||||
|
{
|
||||||
|
g_SelectedObject->AddComponent(std::make_shared<ScriptComponent>());
|
||||||
|
g_LoggerWindow->AddLog("ScriptComponent added to %s.", g_SelectedObject->name.c_str());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
g_LoggerWindow->AddLog("ScriptComponent already exists on %s.", g_SelectedObject->name.c_str());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (selectedComponent == 3) // CameraComponent
|
||||||
|
{
|
||||||
|
// Check if CameraComponent already exists to prevent duplicates
|
||||||
|
std::shared_ptr<CameraComponent> existingCamera = g_SelectedObject->GetComponent<CameraComponent>();
|
||||||
|
if (!existingCamera)
|
||||||
|
{
|
||||||
|
g_SelectedObject->AddComponent(std::make_shared<CameraComponent>());
|
||||||
|
g_LoggerWindow->AddLog("CameraComponent added to %s.", g_SelectedObject->name.c_str());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
g_LoggerWindow->AddLog("CameraComponent already exists on %s.", g_SelectedObject->name.c_str());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Handle unknown selections if necessary
|
||||||
|
g_LoggerWindow->AddLog("Unknown component selection.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui::Separator();
|
||||||
|
|
||||||
|
|
||||||
// ===========================
|
// ===========================
|
||||||
// 1) TRANSFORM
|
// 1) TRANSFORM
|
||||||
@ -344,7 +426,6 @@ void InspectorWindow::Show()
|
|||||||
|
|
||||||
if (script && g_SelectedObject)
|
if (script && g_SelectedObject)
|
||||||
{
|
{
|
||||||
|
|
||||||
// Transform* transform = &g_SelectedObject->transform;
|
// Transform* transform = &g_SelectedObject->transform;
|
||||||
|
|
||||||
ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(1.0f, 1.0f, 1.0f, 1.0f));
|
ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(1.0f, 1.0f, 1.0f, 1.0f));
|
||||||
@ -356,19 +437,25 @@ void InspectorWindow::Show()
|
|||||||
{
|
{
|
||||||
// Define a maximum buffer size
|
// Define a maximum buffer size
|
||||||
const size_t BUFFER_SIZE = 256;
|
const size_t BUFFER_SIZE = 256;
|
||||||
|
|
||||||
// Allocate a buffer and initialize it with the current string
|
// Allocate a buffer and initialize it with the current string
|
||||||
char buffer[BUFFER_SIZE];
|
char buffer[BUFFER_SIZE];
|
||||||
strncpy(buffer, script->ScriptPath.c_str(), BUFFER_SIZE - 1);
|
strncpy(buffer, script->ScriptPath.c_str(), BUFFER_SIZE - 1);
|
||||||
|
|
||||||
buffer[BUFFER_SIZE - 1] = '\0'; // Ensure null-termination
|
buffer[BUFFER_SIZE - 1] = '\0'; // Ensure null-termination
|
||||||
|
|
||||||
|
|
||||||
// Render the InputText widget
|
// Render the InputText widget
|
||||||
if (ImGui::InputText(script->ScriptPath.c_str(), buffer, BUFFER_SIZE))
|
if (ImGui::InputText("Script Path", buffer, BUFFER_SIZE))
|
||||||
{
|
{
|
||||||
|
|
||||||
// Update the string if user made changes
|
// Update the string if user made changes
|
||||||
script->ScriptPath = buffer;
|
script->ScriptPath = buffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ImGui::Button("Reload Script"))
|
if (ImGui::Button("Reload Script"))
|
||||||
{
|
{
|
||||||
|
|
||||||
if (script->Initialize())
|
if (script->Initialize())
|
||||||
{
|
{
|
||||||
g_LoggerWindow->AddLog("Reloaded Script: %s", ImVec4(0.0f, 1.0f, 0.0f, 1.0f), script->ScriptPath.c_str());
|
g_LoggerWindow->AddLog("Reloaded Script: %s", ImVec4(0.0f, 1.0f, 0.0f, 1.0f), script->ScriptPath.c_str());
|
||||||
@ -376,42 +463,6 @@ void InspectorWindow::Show()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ===========================
|
|
||||||
// 2) SCRIPT
|
|
||||||
// ===========================
|
|
||||||
// We keep script text in white
|
|
||||||
// if (ImGui::CollapsingHeader("Script##Main", ImGuiTreeNodeFlags_DefaultOpen))
|
|
||||||
//{
|
|
||||||
// if (ImGui::IsItemHovered())
|
|
||||||
// {
|
|
||||||
// ImGui::BeginTooltip();
|
|
||||||
// ImGui::TextUnformatted("Attach a script or logic component here.");
|
|
||||||
// ImGui::EndTooltip();
|
|
||||||
// }
|
|
||||||
|
|
||||||
// ImGui::TextUnformatted("Script Name:");
|
|
||||||
// ImGui::SameLine();
|
|
||||||
|
|
||||||
// {
|
|
||||||
// char buffer[128];
|
|
||||||
// std::snprintf(buffer, sizeof(buffer), "%s", script.scriptName.c_str());
|
|
||||||
// ImGui::SetNextItemWidth(-1);
|
|
||||||
// if (ImGui::InputText("##ScriptName", buffer, sizeof(buffer)))
|
|
||||||
// {
|
|
||||||
// script.scriptName = buffer;
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
// ImGui::Spacing();
|
|
||||||
|
|
||||||
// ImGui::TextUnformatted("Script Enabled:");
|
|
||||||
// ImGui::SameLine();
|
|
||||||
// ImGui::Checkbox("##ScriptEnabled", &script.enabled);
|
|
||||||
|
|
||||||
// ImGui::Spacing();
|
|
||||||
// ImGui::Separator();
|
|
||||||
//}
|
|
||||||
}
|
}
|
||||||
ImGui::End();
|
ImGui::End();
|
||||||
|
|
||||||
|
@ -3,18 +3,21 @@
|
|||||||
#include <string>
|
#include <string>
|
||||||
#include <glm/glm.hpp> // or <glm/vec3.hpp> if you prefer
|
#include <glm/glm.hpp> // or <glm/vec3.hpp> if you prefer
|
||||||
#include "imgui.h"
|
#include "imgui.h"
|
||||||
|
#include "gcml.h"
|
||||||
|
|
||||||
#include "Componenets/GameObject.h"
|
#include "Componenets/GameObject.h"
|
||||||
#include "Componenets/Mesh.h"
|
#include "Componenets/Mesh.h"
|
||||||
#include "Componenets/Transform.h"
|
#include "Componenets/Transform.h"
|
||||||
#include "Componenets/ScriptComponent.h"
|
#include "Componenets/ScriptComponent.h"
|
||||||
|
#include "Componenets/CameraComponent.h"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// Example struct for a Script component
|
// Example struct for a Script component
|
||||||
struct Script
|
struct Script
|
||||||
{
|
{
|
||||||
std::string scriptName = "MyBehavior.lua";
|
std::string scriptName = "Default.lua";
|
||||||
bool enabled = true;
|
bool enabled = true;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -33,7 +33,7 @@ void LoggerWindow::AddLog(const char* fmt, std::optional<ImVec4> color, ...) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void LoggerWindow::Show() {
|
void LoggerWindow::Show() {
|
||||||
ImGui::Begin("Logger");
|
ImGui::Begin("Logger##logger");
|
||||||
|
|
||||||
if (ImGui::Button("Clear")) {
|
if (ImGui::Button("Clear")) {
|
||||||
m_Logs.clear();
|
m_Logs.clear();
|
||||||
|
@ -36,7 +36,7 @@ void LuaEditorWindow::Show() {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
ImGui::Begin("Lua Text Editor");
|
ImGui::Begin("Lua Text Editor##LuaEditor");
|
||||||
|
|
||||||
// Toolbar buttons
|
// Toolbar buttons
|
||||||
if (ImGui::Button("Save")) {
|
if (ImGui::Button("Save")) {
|
||||||
|
@ -103,7 +103,7 @@ void PerformanceWindow::Show(float fps, float ms)
|
|||||||
|
|
||||||
// Optional style adjustments
|
// Optional style adjustments
|
||||||
ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(10, 10));
|
ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(10, 10));
|
||||||
ImGui::Begin("Performance");
|
ImGui::Begin("Performance##performance");
|
||||||
|
|
||||||
// Colored header
|
// Colored header
|
||||||
ImGui::TextColored(ImVec4(1.0f, 0.8f, 0.2f, 1.0f), "Performance Stats");
|
ImGui::TextColored(ImVec4(1.0f, 0.8f, 0.2f, 1.0f), "Performance Stats");
|
||||||
|
252
src/Windows/ProfilerWindow.cpp
Normal file
252
src/Windows/ProfilerWindow.cpp
Normal file
@ -0,0 +1,252 @@
|
|||||||
|
#include "ProfilerWindow.h"
|
||||||
|
#include <imgui.h>
|
||||||
|
#include <algorithm>
|
||||||
|
#include <string>
|
||||||
|
#include <iostream> // For debug statements
|
||||||
|
|
||||||
|
// Constructor
|
||||||
|
ProfilerWindow::ProfilerWindow()
|
||||||
|
: m_UpdateInterval(0.1) // Set update interval to 0.1 seconds
|
||||||
|
{
|
||||||
|
// Initialize m_LastUpdateTime to force an immediate update on the first frame
|
||||||
|
m_LastUpdateTime = std::chrono::steady_clock::now() - std::chrono::duration_cast<std::chrono::steady_clock::duration>(std::chrono::duration<double>(m_UpdateInterval));
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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));
|
||||||
|
}
|
||||||
|
return averages;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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
|
||||||
|
m_TotalFrameTimeHistory.push_back(totalFrameTime);
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
auto& history = m_ProfileHistories[name];
|
||||||
|
|
||||||
|
// Update total time history
|
||||||
|
history.totalTimeHistory.push_back(result.TotalTime);
|
||||||
|
if (history.totalTimeHistory.size() > ProfileHistory::MaxHistory)
|
||||||
|
history.totalTimeHistory.pop_front();
|
||||||
|
|
||||||
|
// Update average time history
|
||||||
|
double average = result.CallCount > 0 ? result.TotalTime / result.CallCount : 0.0;
|
||||||
|
history.averageTimeHistory.push_back(average);
|
||||||
|
if (history.averageTimeHistory.size() > ProfileHistory::MaxHistory)
|
||||||
|
history.averageTimeHistory.pop_front();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Render the profiler window with table and graphs
|
||||||
|
void ProfilerWindow::Show()
|
||||||
|
{
|
||||||
|
// Check if it's time to update the profiler data
|
||||||
|
auto now = std::chrono::steady_clock::now();
|
||||||
|
std::chrono::duration<double> elapsed = now - m_LastUpdateTime;
|
||||||
|
|
||||||
|
bool shouldUpdate = false;
|
||||||
|
if (elapsed.count() >= m_UpdateInterval)
|
||||||
|
{
|
||||||
|
shouldUpdate = true;
|
||||||
|
m_LastUpdateTime = now;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Begin ImGui window
|
||||||
|
ImGui::Begin("Profiler");
|
||||||
|
|
||||||
|
const auto& data = Profiler::Get().GetLastFrameData();
|
||||||
|
|
||||||
|
if (data.empty())
|
||||||
|
{
|
||||||
|
ImGui::Text("No profiling data available.");
|
||||||
|
ImGui::End();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (shouldUpdate)
|
||||||
|
{
|
||||||
|
// Calculate total frame time
|
||||||
|
double totalFrameTime = 0.0;
|
||||||
|
for (const auto& [name, result] : data)
|
||||||
|
{
|
||||||
|
totalFrameTime += result.TotalTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update history data
|
||||||
|
UpdateHistory(data, totalFrameTime);
|
||||||
|
|
||||||
|
// Reset profiling data for the next interval
|
||||||
|
Profiler::Get().EndFrame();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Render profiling data table
|
||||||
|
RenderTable(data);
|
||||||
|
|
||||||
|
// Render profiling graphs
|
||||||
|
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::End();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Render the profiling data table
|
||||||
|
void ProfilerWindow::RenderTable(const std::unordered_map<std::string, ProfileResult>& data)
|
||||||
|
{
|
||||||
|
// 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;
|
||||||
|
});
|
||||||
|
|
||||||
|
// Add a filter input
|
||||||
|
static char filterBuffer[128] = "";
|
||||||
|
ImGui::InputText("Filter", filterBuffer, IM_ARRAYSIZE(filterBuffer));
|
||||||
|
|
||||||
|
// Convert filter to string
|
||||||
|
std::string filterStr = filterBuffer;
|
||||||
|
|
||||||
|
// Filtered data
|
||||||
|
std::vector<std::pair<std::string, ProfileResult>> filteredData;
|
||||||
|
for (const auto& [name, result] : sortedData)
|
||||||
|
{
|
||||||
|
if (filterStr.empty() || name.find(filterStr) != std::string::npos)
|
||||||
|
filteredData.emplace_back(name, result);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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))
|
||||||
|
{
|
||||||
|
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::TableHeadersRow();
|
||||||
|
|
||||||
|
for (const auto& [name, result] : filteredData)
|
||||||
|
{
|
||||||
|
ImGui::TableNextRow();
|
||||||
|
|
||||||
|
// Function Name with tooltip
|
||||||
|
ImGui::TableSetColumnIndex(0);
|
||||||
|
ImGui::TextUnformatted(name.c_str());
|
||||||
|
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::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);
|
||||||
|
else
|
||||||
|
ImGui::Text("%.3f", result.TotalTime);
|
||||||
|
|
||||||
|
// Average Time
|
||||||
|
ImGui::TableSetColumnIndex(2);
|
||||||
|
double average = result.CallCount > 0 ? result.TotalTime / result.CallCount : 0.0;
|
||||||
|
ImGui::Text("%.3f", average);
|
||||||
|
|
||||||
|
// Call Count
|
||||||
|
ImGui::TableSetColumnIndex(3);
|
||||||
|
ImGui::Text("%d", result.CallCount);
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui::EndTable();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Render the profiling graphs
|
||||||
|
void ProfilerWindow::RenderGraphs()
|
||||||
|
{
|
||||||
|
ImGui::Separator();
|
||||||
|
ImGui::Text("Profiling Graphs");
|
||||||
|
|
||||||
|
// Example: Render a bar graph for the top 5 functions by total time
|
||||||
|
std::vector<std::pair<std::string, ProfileResult>> sortedData;
|
||||||
|
|
||||||
|
const auto& data = Profiler::Get().GetLastFrameData();
|
||||||
|
for (const auto& [name, result] : data)
|
||||||
|
{
|
||||||
|
sortedData.emplace_back(name, result);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sort and take top 5
|
||||||
|
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;
|
||||||
|
});
|
||||||
|
|
||||||
|
size_t displayCount = std::min<size_t>(5, sortedData.size());
|
||||||
|
|
||||||
|
for (size_t i = 0; i < displayCount; ++i)
|
||||||
|
{
|
||||||
|
const auto& [name, result] = sortedData[i];
|
||||||
|
double percentage = 0.0;
|
||||||
|
|
||||||
|
if (!m_TotalFrameTimeHistory.empty())
|
||||||
|
{
|
||||||
|
// Prevent division by zero
|
||||||
|
double lastTotalFrameTime = m_TotalFrameTimeHistory.back();
|
||||||
|
if (lastTotalFrameTime > 0.0)
|
||||||
|
{
|
||||||
|
percentage = (result.TotalTime / lastTotalFrameTime) * 100.0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui::PushID(static_cast<int>(i));
|
||||||
|
ImGui::Text("%s", name.c_str());
|
||||||
|
ImGui::SameLine();
|
||||||
|
ImGui::ProgressBar(static_cast<float>(percentage / 100.0f), ImVec2(-1.0f, 0.0f),
|
||||||
|
(std::to_string(percentage) + "%").c_str());
|
||||||
|
ImGui::PopID();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Example: Render a line plot for total frame time with moving average
|
||||||
|
if (!m_TotalFrameTimeHistory.empty())
|
||||||
|
{
|
||||||
|
ImGui::Text("Frame Time Over Last %zu Frames (Smoothed)", m_TotalFrameTimeHistory.size());
|
||||||
|
|
||||||
|
// Calculate moving average with a window of 10 frames
|
||||||
|
size_t windowSize = 10;
|
||||||
|
std::vector<float> smoothedFrameTimes = MovingAverage(m_TotalFrameTimeHistory, windowSize);
|
||||||
|
|
||||||
|
ImGui::PlotLines("##FrameTimeSmoothed", smoothedFrameTimes.data(), static_cast<int>(smoothedFrameTimes.size()), 0, NULL, 0.0f, 1000.0f, ImVec2(0, 80));
|
||||||
|
}
|
||||||
|
}
|
42
src/Windows/ProfilerWindow.h
Normal file
42
src/Windows/ProfilerWindow.h
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <unordered_map>
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
#include <deque>
|
||||||
|
#include <chrono>
|
||||||
|
#include "Engine/Profiler.h" // Ensure Profiler classes are included
|
||||||
|
|
||||||
|
class ProfilerWindow
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
ProfilerWindow();
|
||||||
|
~ProfilerWindow() = default;
|
||||||
|
|
||||||
|
// Render the profiler window
|
||||||
|
void Show();
|
||||||
|
|
||||||
|
private:
|
||||||
|
struct ProfileHistory
|
||||||
|
{
|
||||||
|
std::deque<double> totalTimeHistory;
|
||||||
|
std::deque<double> averageTimeHistory;
|
||||||
|
static const size_t MaxHistory = 100;
|
||||||
|
};
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
// 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);
|
||||||
|
};
|
@ -10,7 +10,6 @@
|
|||||||
|
|
||||||
#include "gcml.h"
|
#include "gcml.h"
|
||||||
|
|
||||||
|
|
||||||
#include "Componenets/GameObject.h"
|
#include "Componenets/GameObject.h"
|
||||||
#include "Componenets/mesh.h"
|
#include "Componenets/mesh.h"
|
||||||
#include "Componenets/transform.h"
|
#include "Componenets/transform.h"
|
||||||
@ -28,8 +27,8 @@ extern std::vector<std::shared_ptr<GameObject>> g_GameObjects;
|
|||||||
// Extern reference to our global (or extern) asset manager
|
// Extern reference to our global (or extern) asset manager
|
||||||
extern AssetManager g_AssetManager;
|
extern AssetManager g_AssetManager;
|
||||||
|
|
||||||
extern int g_GPU_Triangles_drawn_to_screen;
|
|
||||||
|
|
||||||
|
extern int g_GPU_Triangles_drawn_to_screen;
|
||||||
|
|
||||||
// Example cube data (position + UVs)
|
// Example cube data (position + UVs)
|
||||||
static float g_CubeVertices[] =
|
static float g_CubeVertices[] =
|
||||||
@ -182,10 +181,77 @@ static unsigned int g_CubeIndices[] =
|
|||||||
// Bottom
|
// Bottom
|
||||||
20, 21, 22, 22, 23, 20};
|
20, 21, 22, 22, 23, 20};
|
||||||
|
|
||||||
void RenderWindow::Show()
|
|
||||||
|
|
||||||
|
|
||||||
|
bool PlayPauseButton(const char* label, bool* isPlaying)
|
||||||
|
{
|
||||||
|
// Define button size
|
||||||
|
ImVec2 buttonSize = ImVec2(50, 50); // Adjust size as needed
|
||||||
|
|
||||||
|
// Begin the button
|
||||||
|
if (ImGui::Button(label, buttonSize))
|
||||||
|
{
|
||||||
|
// Toggle the state
|
||||||
|
*isPlaying = !(*isPlaying);
|
||||||
|
return true; // Indicate that the state was toggled
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add tooltip
|
||||||
|
if (ImGui::IsItemHovered())
|
||||||
|
{
|
||||||
|
ImGui::SetTooltip(*isPlaying ? "Pause (Space)" : "Play (Space)");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the current window's draw list
|
||||||
|
ImDrawList* draw_list = ImGui::GetWindowDrawList();
|
||||||
|
|
||||||
|
// Get the position of the button
|
||||||
|
ImVec2 button_pos = ImGui::GetItemRectMin();
|
||||||
|
ImVec2 button_size = ImGui::GetItemRectSize();
|
||||||
|
ImVec2 center = ImVec2(button_pos.x + button_size.x * 0.5f, button_pos.y + button_size.y * 0.5f);
|
||||||
|
|
||||||
|
// Define icon size
|
||||||
|
float icon_size = 20.0f;
|
||||||
|
float half_icon_size = icon_size / 2.0f;
|
||||||
|
|
||||||
|
// Define colors
|
||||||
|
ImU32 icon_color = ImGui::GetColorU32(ImGuiCol_Text);
|
||||||
|
|
||||||
|
if (*isPlaying)
|
||||||
|
{
|
||||||
|
// Draw Pause Icon (two vertical bars)
|
||||||
|
float bar_width = 4.0f;
|
||||||
|
float spacing = 6.0f;
|
||||||
|
|
||||||
|
// Left bar
|
||||||
|
ImVec2 left_bar_p1 = ImVec2(center.x - spacing - bar_width, center.y - half_icon_size);
|
||||||
|
ImVec2 left_bar_p2 = ImVec2(center.x - spacing, center.y + half_icon_size);
|
||||||
|
draw_list->AddRectFilled(left_bar_p1, left_bar_p2, icon_color, 2.0f);
|
||||||
|
|
||||||
|
// Right bar
|
||||||
|
ImVec2 right_bar_p1 = ImVec2(center.x + spacing, center.y - half_icon_size);
|
||||||
|
ImVec2 right_bar_p2 = ImVec2(center.x + spacing + bar_width, center.y + half_icon_size);
|
||||||
|
draw_list->AddRectFilled(right_bar_p1, right_bar_p2, icon_color, 2.0f);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Draw Play Icon (triangle)
|
||||||
|
ImVec2 p1 = ImVec2(center.x - half_icon_size, center.y - half_icon_size);
|
||||||
|
ImVec2 p2 = ImVec2(center.x - half_icon_size, center.y + half_icon_size);
|
||||||
|
ImVec2 p3 = ImVec2(center.x + half_icon_size, center.y);
|
||||||
|
draw_list->AddTriangleFilled(p1, p2, p3, icon_color);
|
||||||
|
}
|
||||||
|
|
||||||
|
return false; // No toggle occurred
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void RenderWindow::Show(bool *GameRunning)
|
||||||
{
|
{
|
||||||
|
|
||||||
ImGui::Begin("Editor");
|
ImGui::Begin("Editor##EditorWindow");
|
||||||
|
|
||||||
ImVec2 size = ImGui::GetContentRegionAvail();
|
ImVec2 size = ImGui::GetContentRegionAvail();
|
||||||
int w = static_cast<int>(size.x);
|
int w = static_cast<int>(size.x);
|
||||||
@ -197,6 +263,13 @@ void RenderWindow::Show()
|
|||||||
m_Initialized = true;
|
m_Initialized = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Center the button
|
||||||
|
ImGui::SetCursorPosX((ImGui::GetWindowWidth() - 60) * 0.5f);
|
||||||
|
|
||||||
|
// Render the Play/Pause button
|
||||||
|
// Render the Play/Pause button
|
||||||
|
PlayPauseButton("##PlayPauseButton", GameRunning);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// If there's space, render to the FBO, then show it as an ImGui image
|
// If there's space, render to the FBO, then show it as an ImGui image
|
||||||
@ -220,8 +293,9 @@ void RenderWindow::Show()
|
|||||||
ImGui::Text("No space to render.");
|
ImGui::Text("No space to render.");
|
||||||
}
|
}
|
||||||
|
|
||||||
ImGui::End();
|
|
||||||
|
|
||||||
|
|
||||||
|
ImGui::End();
|
||||||
}
|
}
|
||||||
|
|
||||||
void RenderWindow::InitGLResources()
|
void RenderWindow::InitGLResources()
|
||||||
@ -231,7 +305,7 @@ void RenderWindow::InitGLResources()
|
|||||||
// ----------------------------------------------------
|
// ----------------------------------------------------
|
||||||
|
|
||||||
{
|
{
|
||||||
Shader* shaderAsset = g_AssetManager.loadAsset<Shader*>(AssetType::SHADER, "assets/shaders/UnlitMaterial");
|
Shader *shaderAsset = g_AssetManager.loadAsset<Shader *>(AssetType::SHADER, "assets/shaders/UnlitMaterial");
|
||||||
if (!shaderAsset)
|
if (!shaderAsset)
|
||||||
{
|
{
|
||||||
fprintf(stderr, "[RenderWindow] Failed to load shader via AssetManager.\n");
|
fprintf(stderr, "[RenderWindow] Failed to load shader via AssetManager.\n");
|
||||||
@ -285,14 +359,11 @@ void RenderWindow::InitGLResources()
|
|||||||
// ----------------------------------------------------
|
// ----------------------------------------------------
|
||||||
// 4) Initialize GameObjects
|
// 4) Initialize GameObjects
|
||||||
// ----------------------------------------------------
|
// ----------------------------------------------------
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void RenderWindow::RenderSceneToFBO()
|
void RenderWindow::RenderSceneToFBO()
|
||||||
{
|
{
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
m_RotationAngle += 0.001f; // spin per frame
|
m_RotationAngle += 0.001f; // spin per frame
|
||||||
|
|
||||||
// Bind the FBO
|
// Bind the FBO
|
||||||
@ -319,7 +390,6 @@ void RenderWindow::RenderSceneToFBO()
|
|||||||
|
|
||||||
// Iterate over each GameObject and render it
|
// Iterate over each GameObject and render it
|
||||||
|
|
||||||
|
|
||||||
for (auto &obj : g_GameObjects)
|
for (auto &obj : g_GameObjects)
|
||||||
{
|
{
|
||||||
|
|
||||||
@ -328,15 +398,10 @@ void RenderWindow::RenderSceneToFBO()
|
|||||||
// -----------------------------------
|
// -----------------------------------
|
||||||
glm::mat4 model = glm::mat4(1.f);
|
glm::mat4 model = glm::mat4(1.f);
|
||||||
|
|
||||||
|
|
||||||
std::shared_ptr<TransformComponent> transform = obj->GetComponent<TransformComponent>();
|
std::shared_ptr<TransformComponent> transform = obj->GetComponent<TransformComponent>();
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
std::shared_ptr<MeshComponent> mesh = obj->GetComponent<MeshComponent>();
|
std::shared_ptr<MeshComponent> mesh = obj->GetComponent<MeshComponent>();
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
if (transform && mesh)
|
if (transform && mesh)
|
||||||
{
|
{
|
||||||
|
|
||||||
@ -348,7 +413,7 @@ void RenderWindow::RenderSceneToFBO()
|
|||||||
|
|
||||||
// Rotate around X, Y, Z
|
// Rotate around X, Y, Z
|
||||||
|
|
||||||
//transform->rotation.x += m_RotationAngle;
|
// 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.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.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));
|
model = glm::rotate(model, glm::radians(transform->rotation.z), glm::vec3(0.f, 0.f, 1.f));
|
||||||
@ -356,8 +421,6 @@ void RenderWindow::RenderSceneToFBO()
|
|||||||
// Scale
|
// Scale
|
||||||
model = glm::scale(model, transform->scale);
|
model = glm::scale(model, transform->scale);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// Compute MVP
|
// Compute MVP
|
||||||
glm::mat4 mvp = proj * view * model;
|
glm::mat4 mvp = proj * view * model;
|
||||||
|
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
class RenderWindow
|
class RenderWindow
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
void Show();
|
void Show(bool *GameRunning);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void InitGLResources();
|
void InitGLResources();
|
||||||
|
@ -13,7 +13,6 @@
|
|||||||
extern std::vector<std::shared_ptr<GameObject>> g_GameObjects;
|
extern std::vector<std::shared_ptr<GameObject>> g_GameObjects;
|
||||||
extern std::shared_ptr<GameObject> g_SelectedObject;
|
extern std::shared_ptr<GameObject> g_SelectedObject;
|
||||||
|
|
||||||
|
|
||||||
extern AssetManager g_AssetManager;
|
extern AssetManager g_AssetManager;
|
||||||
|
|
||||||
// Helper: Create a default cube GameObject
|
// Helper: Create a default cube GameObject
|
||||||
@ -38,7 +37,7 @@ std::shared_ptr<GameObject> CreateDefaultCube()
|
|||||||
|
|
||||||
void SceneWindow::Show()
|
void SceneWindow::Show()
|
||||||
{
|
{
|
||||||
if (ImGui::Begin("Scene Window"))
|
if (ImGui::Begin("Scene Window##SceneWindow"))
|
||||||
{
|
{
|
||||||
// Add Button
|
// Add Button
|
||||||
if (ImGui::Button("Add Object"))
|
if (ImGui::Button("Add Object"))
|
||||||
@ -52,60 +51,57 @@ void SceneWindow::Show()
|
|||||||
// Begin child region for the list to make it scrollable
|
// Begin child region for the list to make it scrollable
|
||||||
ImGui::BeginChild("GameObjectList", ImVec2(0, -ImGui::GetFrameHeightWithSpacing()), false, ImGuiWindowFlags_HorizontalScrollbar);
|
ImGui::BeginChild("GameObjectList", ImVec2(0, -ImGui::GetFrameHeightWithSpacing()), false, ImGuiWindowFlags_HorizontalScrollbar);
|
||||||
|
|
||||||
// Define TreeNode flags for better visuals and interaction
|
// Initialize an external index to keep track of each GameObject's position
|
||||||
ImGuiTreeNodeFlags nodeFlags = ImGuiTreeNodeFlags_OpenOnArrow | ImGuiTreeNodeFlags_SpanAvailWidth;
|
size_t index = 0;
|
||||||
|
|
||||||
// Iterate through GameObjects using index for unique identification
|
// Iterate through GameObjects using a range-based for loop
|
||||||
for (size_t i = 0; i < g_GameObjects.size(); ++i)
|
for (auto &obj : g_GameObjects)
|
||||||
{
|
{
|
||||||
auto &obj = g_GameObjects[i];
|
// Determine if the current GameObject is selected
|
||||||
|
bool isSelected = (g_SelectedObject == obj);
|
||||||
|
|
||||||
// Determine flags based on selection
|
// Create a unique label for each selectable item using the index
|
||||||
ImGuiTreeNodeFlags flags = nodeFlags;
|
// This ensures ImGui uniquely identifies each item
|
||||||
if (g_SelectedObject == obj)
|
std::string label = obj->name + "##" + std::to_string(index);
|
||||||
flags |= ImGuiTreeNodeFlags_Selected;
|
|
||||||
|
|
||||||
// Unique identifier for each GameObject node using pointer to ensure uniqueness
|
// Render the GameObject as a selectable item in the list
|
||||||
// Alternatively, you can use the object's ID or address
|
if (ImGui::Selectable(label.c_str(), isSelected))
|
||||||
std::string nodeLabel = obj->name;
|
|
||||||
bool nodeOpen = ImGui::TreeNodeEx((void *)(intptr_t)i, flags, nodeLabel.c_str());
|
|
||||||
|
|
||||||
// Handle selection
|
|
||||||
if (ImGui::IsItemClicked(ImGuiMouseButton_Left))
|
|
||||||
{
|
{
|
||||||
|
// Update the selected GameObject when clicked
|
||||||
g_SelectedObject = obj;
|
g_SelectedObject = obj;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Right-click context menu for GameObject actions
|
// Handle right-click context menu for the current item
|
||||||
if (ImGui::BeginPopupContextItem())
|
if (ImGui::BeginPopupContextItem())
|
||||||
{
|
{
|
||||||
// Delete GameObject Option
|
// Option to remove the GameObject
|
||||||
if (ImGui::MenuItem("Remove"))
|
if (ImGui::MenuItem("Remove"))
|
||||||
{
|
{
|
||||||
|
// Remove the GameObject by its index
|
||||||
|
RemoveGameObject(static_cast<int>(index));
|
||||||
|
|
||||||
RemoveGameObject(static_cast<int>(i));
|
// End the popup before breaking out of the loop
|
||||||
|
|
||||||
ImGui::EndPopup();
|
ImGui::EndPopup();
|
||||||
// Since we've erased the current entity, adjust the loop accordingly
|
|
||||||
// Decrement i to account for the removed element
|
// Since we've modified the container, exit the loop to prevent issues
|
||||||
--i;
|
break;
|
||||||
continue; // Skip the rest of the loop iteration
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// End the context menu popup
|
||||||
ImGui::EndPopup();
|
ImGui::EndPopup();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Optionally, implement double-click to rename or perform other actions
|
// Increment the index for the next GameObject
|
||||||
|
++index;
|
||||||
|
}
|
||||||
|
|
||||||
// Close the tree node
|
// Optional: Display a message if there are no GameObjects
|
||||||
if (nodeOpen)
|
if (g_GameObjects.empty())
|
||||||
{
|
{
|
||||||
// If you decide to add child nodes in the future, handle them here
|
ImGui::Text("No Game Objects available.");
|
||||||
// Currently, no additional handling is required
|
}
|
||||||
|
|
||||||
ImGui::TreePop();
|
// End the ImGui window or group
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ImGui::EndChild();
|
ImGui::EndChild();
|
||||||
|
|
||||||
@ -149,7 +145,7 @@ void SceneWindow::RemoveGameObject(int index)
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
DEBUG_PRINT("Attempted to remove GameObject with invalid index: %d", index );
|
DEBUG_PRINT("Attempted to remove GameObject with invalid index: %d", index);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user