Did so much i forgot all i did
This commit is contained in:
parent
11bad26b38
commit
e03729b42b
69
imgui.ini
69
imgui.ini
@ -10,24 +10,24 @@ Collapsed=1
|
||||
|
||||
[Window][WindowOverViewport_11111111]
|
||||
Pos=0,19
|
||||
Size=1920,1158
|
||||
Size=1280,701
|
||||
Collapsed=0
|
||||
|
||||
[Window][Inspector]
|
||||
Pos=1553,19
|
||||
Size=367,659
|
||||
Pos=913,19
|
||||
Size=367,202
|
||||
Collapsed=0
|
||||
DockId=0x00000018,0
|
||||
|
||||
[Window][Scene Tree]
|
||||
Pos=0,19
|
||||
Size=342,575
|
||||
Size=342,356
|
||||
Collapsed=0
|
||||
DockId=0x00000003,0
|
||||
DockId=0x0000000F,0
|
||||
|
||||
[Window][Viewport]
|
||||
Pos=344,19
|
||||
Size=1207,659
|
||||
Size=567,202
|
||||
Collapsed=0
|
||||
DockId=0x00000017,0
|
||||
|
||||
@ -36,14 +36,14 @@ Size=1280,19
|
||||
Collapsed=0
|
||||
|
||||
[Window][Performance Info]
|
||||
Pos=1430,881
|
||||
Size=490,296
|
||||
Pos=1094,223
|
||||
Size=186,497
|
||||
Collapsed=0
|
||||
DockId=0x0000000F,0
|
||||
DockId=0x00000016,0
|
||||
|
||||
[Window][Console]
|
||||
Pos=344,680
|
||||
Size=1497,326
|
||||
Pos=344,223
|
||||
Size=715,203
|
||||
Collapsed=0
|
||||
DockId=0x00000013,0
|
||||
|
||||
@ -54,8 +54,8 @@ Collapsed=0
|
||||
DockId=0x00000017,1
|
||||
|
||||
[Window][Profiler]
|
||||
Pos=344,1008
|
||||
Size=1497,169
|
||||
Pos=344,428
|
||||
Size=715,292
|
||||
Collapsed=0
|
||||
DockId=0x00000014,0
|
||||
|
||||
@ -78,19 +78,18 @@ Collapsed=0
|
||||
DockId=0x00000015,1
|
||||
|
||||
[Window][Color Correction]
|
||||
Pos=1669,881
|
||||
Size=251,296
|
||||
Pos=1196,320
|
||||
Size=317,227
|
||||
Collapsed=0
|
||||
DockId=0x00000010,0
|
||||
|
||||
[Window][Asset Browser]
|
||||
Pos=0,596
|
||||
Size=342,581
|
||||
Pos=0,658
|
||||
Size=342,519
|
||||
Collapsed=0
|
||||
DockId=0x00000004,0
|
||||
|
||||
[Window][Confirm Deletion]
|
||||
Pos=797,551
|
||||
Pos=787,416
|
||||
Size=325,75
|
||||
Collapsed=0
|
||||
|
||||
@ -113,8 +112,8 @@ Collapsed=0
|
||||
DockId=0x0000000E,0
|
||||
|
||||
[Window][Audio Output]
|
||||
Pos=1843,680
|
||||
Size=77,497
|
||||
Pos=1061,223
|
||||
Size=31,497
|
||||
Collapsed=0
|
||||
DockId=0x00000012,0
|
||||
|
||||
@ -124,25 +123,31 @@ Size=277,150
|
||||
Collapsed=0
|
||||
DockId=0x0000000D,0
|
||||
|
||||
[Window][Resources]
|
||||
Pos=0,377
|
||||
Size=342,343
|
||||
Collapsed=0
|
||||
DockId=0x00000010,0
|
||||
|
||||
[Docking][Data]
|
||||
DockSpace ID=0x11111111 Window=0x1BBC0F80 Pos=0,19 Size=1920,1158 Split=X
|
||||
DockSpace ID=0x11111111 Window=0x1BBC0F80 Pos=0,19 Size=1280,701 Split=X
|
||||
DockNode ID=0x00000005 Parent=0x11111111 SizeRef=989,1158 Split=X
|
||||
DockNode ID=0x00000001 Parent=0x00000005 SizeRef=342,701 Split=Y Selected=0x12EF0F59
|
||||
DockNode ID=0x00000003 Parent=0x00000001 SizeRef=342,575 HiddenTabBar=1 Selected=0x12EF0F59
|
||||
DockNode ID=0x00000004 Parent=0x00000001 SizeRef=342,581 HiddenTabBar=1 Selected=0x36AF052B
|
||||
DockNode ID=0x00000003 Parent=0x00000001 SizeRef=342,637 Split=Y Selected=0x12EF0F59
|
||||
DockNode ID=0x0000000F Parent=0x00000003 SizeRef=342,356 HiddenTabBar=1 Selected=0x12EF0F59
|
||||
DockNode ID=0x00000010 Parent=0x00000003 SizeRef=342,343 HiddenTabBar=1 Selected=0x30401527
|
||||
DockNode ID=0x00000004 Parent=0x00000001 SizeRef=342,519 HiddenTabBar=1 Selected=0x36AF052B
|
||||
DockNode ID=0x00000002 Parent=0x00000005 SizeRef=1484,701 Split=Y Selected=0xC450F867
|
||||
DockNode ID=0x00000007 Parent=0x00000002 SizeRef=606,659 Split=X Selected=0xC450F867
|
||||
DockNode ID=0x00000017 Parent=0x00000007 SizeRef=1207,860 CentralNode=1 HiddenTabBar=1 Selected=0xC450F867
|
||||
DockNode ID=0x00000018 Parent=0x00000007 SizeRef=367,860 HiddenTabBar=1 Selected=0x36DC96AB
|
||||
DockNode ID=0x00000008 Parent=0x00000002 SizeRef=606,497 Split=X Selected=0xEA83D666
|
||||
DockNode ID=0x00000015 Parent=0x00000008 SizeRef=1291,172 Split=X Selected=0xEA83D666
|
||||
DockNode ID=0x00000011 Parent=0x00000015 SizeRef=1497,168 Split=Y Selected=0x9B5D3198
|
||||
DockNode ID=0x00000013 Parent=0x00000011 SizeRef=1449,326 HiddenTabBar=1 Selected=0xEA83D666
|
||||
DockNode ID=0x00000014 Parent=0x00000011 SizeRef=1449,169 HiddenTabBar=1 Selected=0x9B5D3198
|
||||
DockNode ID=0x00000012 Parent=0x00000015 SizeRef=77,168 HiddenTabBar=1 Selected=0x56009A08
|
||||
DockNode ID=0x00000016 Parent=0x00000008 SizeRef=283,172 Split=X Selected=0x56009A08
|
||||
DockNode ID=0x0000000F Parent=0x00000016 SizeRef=140,296 HiddenTabBar=1 Selected=0x3FC1A724
|
||||
DockNode ID=0x00000010 Parent=0x00000016 SizeRef=148,296 HiddenTabBar=1 Selected=0xA873C17F
|
||||
DockNode ID=0x00000015 Parent=0x00000008 SizeRef=1260,172 Split=X Selected=0xEA83D666
|
||||
DockNode ID=0x00000011 Parent=0x00000015 SizeRef=715,168 Split=Y Selected=0x9B5D3198
|
||||
DockNode ID=0x00000013 Parent=0x00000011 SizeRef=1449,203 HiddenTabBar=1 Selected=0xEA83D666
|
||||
DockNode ID=0x00000014 Parent=0x00000011 SizeRef=1449,292 HiddenTabBar=1 Selected=0x9B5D3198
|
||||
DockNode ID=0x00000012 Parent=0x00000015 SizeRef=31,168 HiddenTabBar=1 Selected=0x56009A08
|
||||
DockNode ID=0x00000016 Parent=0x00000008 SizeRef=314,172 HiddenTabBar=1 Selected=0x3FC1A724
|
||||
DockNode ID=0x00000006 Parent=0x11111111 SizeRef=289,1158 Split=Y Selected=0x36DC96AB
|
||||
DockNode ID=0x00000009 Parent=0x00000006 SizeRef=449,488 Split=Y Selected=0x36DC96AB
|
||||
DockNode ID=0x0000000B Parent=0x00000009 SizeRef=449,556 Split=Y Selected=0x36DC96AB
|
||||
|
@ -1,5 +1,2 @@
|
||||
[COMPILE] g++ -std=c++20 -Wall -g -Isrc/include -Isrc/include/lua -Isrc/vendor -Isrc/vendor/imgui -Isrc/vendor/box2d -Isrc/vendor/xxhash -Isrc/vendor/miniaudio -IC:/msys64/mingw64/include -Isrc\vendor\imgui -IC:\msys64\mingw64\lib\libyaml-cpp.a -MMD -MP -c src\src\utils\Shader.cpp -o src\build\utils\Shader.o
|
||||
[COMPILE] g++ -std=c++20 -Wall -g -Isrc/include -Isrc/include/lua -Isrc/vendor -Isrc/vendor/imgui -Isrc/vendor/box2d -Isrc/vendor/xxhash -Isrc/vendor/miniaudio -IC:/msys64/mingw64/include -Isrc\vendor\imgui -IC:\msys64\mingw64\lib\libyaml-cpp.a -MMD -MP -c src\src\core\utils\utils.cpp -o src\build\core\utils\utils.o
|
||||
[COMPILE] g++ -std=c++20 -Wall -g -Isrc/include -Isrc/include/lua -Isrc/vendor -Isrc/vendor/imgui -Isrc/vendor/box2d -Isrc/vendor/xxhash -Isrc/vendor/miniaudio -IC:/msys64/mingw64/include -Isrc\vendor\imgui -IC:\msys64\mingw64\lib\libyaml-cpp.a -MMD -MP -c src\src\Engine.cpp -o src\build\Engine.o
|
||||
[COMPILE] g++ -std=c++20 -Wall -g -Isrc/include -Isrc/include/lua -Isrc/vendor -Isrc/vendor/imgui -Isrc/vendor/box2d -Isrc/vendor/xxhash -Isrc/vendor/miniaudio -IC:/msys64/mingw64/include -Isrc\vendor\imgui -IC:\msys64\mingw64\lib\libyaml-cpp.a -MMD -MP -c src\src\Renderer.cpp -o src\build\Renderer.o
|
||||
[LINK] g++ src\build\Engine.o src\build\main.o src\build\Renderer.o src\build\Components\AnimationComponent.o src\build\Components\AudioPlayerComponent.o src\build\Components\CameraComponent.o src\build\Components\LightComponent.o src\build\Components\ParticleComponent.o src\build\Components\PhysicsComponent.o src\build\Components\ScriptComponent.o src\build\Components\SpriteComponent.o src\build\Components\TextComonent.o src\build\Components\TilemapComponent.o src\build\core\audio\AudioEngine.o src\build\core\utils\AssetManager.o src\build\core\utils\EngineConfig.o src\build\core\utils\ExceptionHandler.o src\build\core\utils\FileDialog.o src\build\core\utils\input.o src\build\core\utils\LoadingWindow.o src\build\core\utils\Logging.o src\build\core\utils\Profiler.o src\build\core\utils\Texture.o src\build\core\utils\utils.o src\build\editor\windows\AssetBrowser.o src\build\editor\windows\AudioInfo.o src\build\editor\windows\Inspector.o src\build\Entitys\Object.o src\build\utils\GameObjectsList.o src\build\utils\Shader.o src\build\utils\UID.o src\build\lapi.o src\build\lauxlib.o src\build\lbaselib.o src\build\lcode.o src\build\lcorolib.o src\build\lctype.o src\build\ldblib.o src\build\ldebug.o src\build\ldo.o src\build\ldump.o src\build\lfunc.o src\build\lgc.o src\build\linit.o src\build\liolib.o src\build\llex.o src\build\lmathlib.o src\build\lmem.o src\build\loadlib.o src\build\lobject.o src\build\lopcodes.o src\build\loslib.o src\build\lparser.o src\build\lstate.o src\build\lstring.o src\build\lstrlib.o src\build\ltable.o src\build\ltablib.o src\build\ltm.o src\build\lua.o src\build\luac.o src\build\lundump.o src\build\lutf8lib.o src\build\lvm.o src\build\lzio.o src\build\imgui.o src\build\imgui_demo.o src\build\imgui_draw.o src\build\imgui_impl_glfw.o src\build\imgui_impl_opengl3.o src\build\imgui_tables.o src\build\imgui_widgets.o src\build\aabb.o src\build\arena_allocator.o src\build\array.o src\build\bitset.o src\build\body.o src\build\broad_phase.o src\build\constraint_graph.o src\build\contact.o src\build\contact_solver.o src\build\core.o src\build\distance.o src\build\distance_joint.o src\build\dynamic_tree.o src\build\geometry.o src\build\hull.o src\build\id_pool.o src\build\island.o src\build\joint.o src\build\manifold.o src\build\math_functions.o src\build\motor_joint.o src\build\mouse_joint.o src\build\mover.o src\build\prismatic_joint.o src\build\revolute_joint.o src\build\sensor.o src\build\shape.o src\build\solver.o src\build\solver_set.o src\build\table.o src\build\timer.o src\build\types.o src\build\weld_joint.o src\build\wheel_joint.o src\build\world.o src\build\xxhash.o src\build\miniaudio.o -o src\build\app.exe -LC:\msys64\mingw64\lib -lglfw3 -lglew32 -lopengl32 -lgdi32 -lyaml-cpp -lcomdlg32 -lssl -lcrypto -ldbghelp
|
||||
[RUN] Executed app.exe successfully.
|
||||
|
34
src/assets/lua/light_test.lua
Normal file
34
src/assets/lua/light_test.lua
Normal file
@ -0,0 +1,34 @@
|
||||
local obj = nil
|
||||
local light = nil
|
||||
local hue = 0.0
|
||||
|
||||
function HSVtoRGB(h, s, v)
|
||||
local i = math.floor(h * 6)
|
||||
local f = h * 6 - i
|
||||
local p = v * (1 - s)
|
||||
local q = v * (1 - f * s)
|
||||
local t = v * (1 - (1 - f) * s)
|
||||
i = i % 6
|
||||
|
||||
if i == 0 then return Vector3(v, t, p) end
|
||||
if i == 1 then return Vector3(q, v, p) end
|
||||
if i == 2 then return Vector3(p, v, t) end
|
||||
if i == 3 then return Vector3(p, q, v) end
|
||||
if i == 4 then return Vector3(t, p, v) end
|
||||
if i == 5 then return Vector3(v, p, q) end
|
||||
end
|
||||
|
||||
|
||||
function OnInit()
|
||||
obj = Engine.GetObjectByTag("Light")
|
||||
if obj then
|
||||
light = obj:GetComponent("LightComponent")
|
||||
end
|
||||
end
|
||||
|
||||
function OnUpdate(dt)
|
||||
if not light then return end
|
||||
|
||||
hue = (hue + dt * 0.2) % 1.0
|
||||
light:SetColor(HSVtoRGB(hue, 1.0, 1.0))
|
||||
end
|
2121
src/assets/scenes/drag_n_drop_tests.cene
Normal file
2121
src/assets/scenes/drag_n_drop_tests.cene
Normal file
File diff suppressed because it is too large
Load Diff
1643
src/assets/scenes/isometric_test.cene
Normal file
1643
src/assets/scenes/isometric_test.cene
Normal file
File diff suppressed because it is too large
Load Diff
1614
src/assets/scenes/lots.cene
Normal file
1614
src/assets/scenes/lots.cene
Normal file
File diff suppressed because it is too large
Load Diff
43
src/assets/shaders/outline.frag
Normal file
43
src/assets/shaders/outline.frag
Normal file
@ -0,0 +1,43 @@
|
||||
#version 330 core
|
||||
in vec2 TexCoords;
|
||||
out vec4 FragColor;
|
||||
|
||||
uniform sampler2D uTexture;
|
||||
uniform vec4 outlineColor = vec4(1.0, 1.0, 0.0, 1.0); // Yellow outline
|
||||
uniform float threshold = 0.1; // Alpha threshold
|
||||
uniform float outlineWidth = 1.0 / 256.0; // Adjust based on resolution
|
||||
|
||||
void main()
|
||||
{
|
||||
float alpha = texture(uTexture, TexCoords).a;
|
||||
|
||||
// If we're fully inside the texture, draw normally
|
||||
if (alpha > threshold)
|
||||
{
|
||||
FragColor = texture(uTexture, TexCoords);
|
||||
return;
|
||||
}
|
||||
|
||||
// Sample neighbors to detect edges
|
||||
bool isEdge = false;
|
||||
for (int x = -1; x <= 1; ++x)
|
||||
{
|
||||
for (int y = -1; y <= 1; ++y)
|
||||
{
|
||||
if (x == 0 && y == 0) continue;
|
||||
vec2 offset = vec2(x, y) * outlineWidth;
|
||||
float neighborAlpha = texture(uTexture, TexCoords + offset).a;
|
||||
if (neighborAlpha > threshold)
|
||||
{
|
||||
isEdge = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (isEdge) break;
|
||||
}
|
||||
|
||||
if (isEdge)
|
||||
FragColor = outlineColor;
|
||||
else
|
||||
discard;
|
||||
}
|
13
src/assets/shaders/outline.vert
Normal file
13
src/assets/shaders/outline.vert
Normal file
@ -0,0 +1,13 @@
|
||||
#version 330 core
|
||||
layout(location = 0) in vec3 aPos; // vertex position
|
||||
layout(location = 1) in vec2 aTexCoord; // texture coordinate
|
||||
|
||||
uniform mat4 uMVP; // Model-View-Projection matrix
|
||||
|
||||
out vec2 TexCoords;
|
||||
|
||||
void main()
|
||||
{
|
||||
TexCoords = aTexCoord;
|
||||
gl_Position = uMVP * vec4(aPos, 1.0);
|
||||
}
|
@ -22,8 +22,6 @@ uniform int uClusterHeight;
|
||||
uniform int uClusterCols;
|
||||
uniform int uMaxLightsPerCluster;
|
||||
|
||||
|
||||
|
||||
#define MAX_LIGHTS 512
|
||||
uniform vec2 uLightPos[MAX_LIGHTS];
|
||||
uniform vec3 uLightColor[MAX_LIGHTS];
|
||||
@ -36,13 +34,15 @@ layout(std430, binding = 1) readonly buffer ClusterLightBuffer {
|
||||
|
||||
void main()
|
||||
{
|
||||
|
||||
// Flip UV to match expected orientation
|
||||
vec2 rotatedUV = mix(uUVMin, uUVMax, vec2(vUV.y, 1.0 - vUV.x));
|
||||
|
||||
// Sample texture color
|
||||
vec4 texColor = texture(uTex, rotatedUV);
|
||||
if (texColor.a < 0.1)
|
||||
discard;
|
||||
|
||||
// Sample and transform normal
|
||||
vec3 n = texture(uNormalMap, rotatedUV).rgb * 2.0 - 1.0;
|
||||
n.y = -n.y;
|
||||
|
||||
@ -54,6 +54,7 @@ void main()
|
||||
vec3 normal = normalize(n);
|
||||
vec3 finalLight = vec3(0.0);
|
||||
|
||||
// Determine cluster index
|
||||
int cx = int(vFragScreenPos.x) / uClusterWidth;
|
||||
int cy = int(vFragScreenPos.y) / uClusterHeight;
|
||||
int clusterIndex = cy * uClusterCols + cx;
|
||||
@ -75,13 +76,16 @@ void main()
|
||||
}
|
||||
}
|
||||
|
||||
vec3 result = texColor.rgb * finalLight;
|
||||
// Apply lighting and multiply by alpha to suppress gray halo
|
||||
vec3 litColor = texColor.rgb * finalLight * texColor.a;
|
||||
|
||||
result *= uBrightness;
|
||||
// Post-processing
|
||||
litColor *= uBrightness;
|
||||
|
||||
float gray = dot(result, vec3(0.299, 0.587, 0.114));
|
||||
result = mix(vec3(gray), result, uSaturation);
|
||||
float gray = dot(litColor, vec3(0.299, 0.587, 0.114));
|
||||
litColor = mix(vec3(gray), litColor, uSaturation);
|
||||
|
||||
result = pow(result, vec3(1.0 / uGamma));
|
||||
FragColor = vec4(clamp(result, 0.0, 1.0), texColor.a);
|
||||
litColor = pow(litColor, vec3(1.0 / uGamma));
|
||||
|
||||
FragColor = vec4(clamp(litColor, 0.0, 1.0), texColor.a);
|
||||
}
|
||||
|
@ -9,15 +9,14 @@ uniform vec2 uUVMax;
|
||||
|
||||
void main()
|
||||
{
|
||||
// Rotate UV 90 degrees to the right: (x, y) → (y, 1 - x)
|
||||
vec2 rotatedUV = vec2(vUV.y, 1.0 - vUV.x);
|
||||
|
||||
// Interpolate UVs within atlas range
|
||||
vec2 uv = mix(uUVMin, uUVMax, rotatedUV);
|
||||
|
||||
vec4 color = texture(uTex, uv);
|
||||
|
||||
if (color.a < 0.01)
|
||||
discard;
|
||||
|
||||
|
||||
FragColor = color;
|
||||
}
|
||||
|
@ -17,6 +17,8 @@
|
||||
#include "../core/utils/input.h"
|
||||
|
||||
#include "../core/types/vec2.h"
|
||||
#include "../core/types/vec3.h"
|
||||
|
||||
|
||||
#include <lua.hpp>
|
||||
#include <memory>
|
||||
@ -39,14 +41,36 @@ struct LuaVector2
|
||||
{
|
||||
float x, y;
|
||||
};
|
||||
#define LUA_VECTOR2_MT "LuaVector2Meta"
|
||||
struct LuaVector3
|
||||
{
|
||||
float x, y, z;
|
||||
};
|
||||
|
||||
#define LUA_ANIMATION_MT "LuaAnimationMeta"
|
||||
#define LUA_VECTOR3_MT "LuaVector3Meta"
|
||||
#define LUA_VECTOR2_MT "LuaVector2Meta"
|
||||
|
||||
struct LuaAnimationWrapper
|
||||
{
|
||||
AnimationComponent *comp;
|
||||
};
|
||||
struct LuaLightWrapper
|
||||
{
|
||||
LightComponent *comp;
|
||||
};
|
||||
|
||||
#define LUA_LIGHT_MT "LuaLightMeta"
|
||||
#define LUA_ANIMATION_MT "LuaAnimationMeta"
|
||||
|
||||
|
||||
|
||||
|
||||
static core::types::Vec3 GetLuaVector3(lua_State* L, int index);
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
ScriptComponent::ScriptComponent(Object *owner) : Component(owner), L(nullptr) {}
|
||||
ScriptComponent::~ScriptComponent()
|
||||
@ -153,7 +177,6 @@ static Component *GetComponentByName(Object *obj, const std::string &type)
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
||||
static int Lua_GetMousePos(lua_State *L)
|
||||
{
|
||||
PROFILE_DEEP_SCOPE("Engine::GetMousePos");
|
||||
@ -189,7 +212,21 @@ static int Lua_Object_GetComponent(lua_State *L)
|
||||
lua_pushnil(L);
|
||||
return 1;
|
||||
}
|
||||
// fallback for other components
|
||||
if (strcmp(type, "LightComponent") == 0)
|
||||
{
|
||||
auto compPtr = wrapper->obj->GetComponent<LightComponent>();
|
||||
if (compPtr)
|
||||
{
|
||||
LuaLightWrapper *lw = (LuaLightWrapper *)lua_newuserdata(L, sizeof(LuaLightWrapper));
|
||||
lw->comp = compPtr.get();
|
||||
luaL_getmetatable(L, LUA_LIGHT_MT);
|
||||
lua_setmetatable(L, -2);
|
||||
return 1;
|
||||
}
|
||||
lua_pushnil(L);
|
||||
return 1;
|
||||
}
|
||||
|
||||
Component *comp = GetComponentByName(wrapper->obj, type);
|
||||
lua_pushlightuserdata(L, comp ? comp : nullptr);
|
||||
return 1;
|
||||
@ -268,6 +305,123 @@ static int Lua_GetObjectByTag(lua_State *L)
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
static LightComponent *CheckLight(lua_State *L)
|
||||
{
|
||||
return ((LuaLightWrapper *)luaL_checkudata(L, 1, LUA_LIGHT_MT))->comp;
|
||||
}
|
||||
|
||||
static int Lua_Light_GetColor(lua_State *L)
|
||||
{
|
||||
auto *light = CheckLight(L);
|
||||
glm::vec3 c = light->GetColor();
|
||||
LuaVector3 *vec = (LuaVector3 *)lua_newuserdata(L, sizeof(LuaVector3));
|
||||
vec->x = c.x; vec->y = c.y; vec->z = c.z;
|
||||
luaL_getmetatable(L, LUA_VECTOR3_MT);
|
||||
lua_setmetatable(L, -2);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int Lua_Light_SetColor(lua_State *L)
|
||||
{
|
||||
auto* light = CheckLight(L);
|
||||
core::types::Vec3 color = GetLuaVector3(L, 2);
|
||||
light->SetColor(color);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int Lua_Light_GetIntensity(lua_State *L)
|
||||
{
|
||||
lua_pushnumber(L, CheckLight(L)->GetIntensity());
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int Lua_Light_SetIntensity(lua_State *L)
|
||||
{
|
||||
CheckLight(L)->SetIntensity(static_cast<float>(luaL_checknumber(L, 2)));
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int Lua_Light_GetRadius(lua_State *L)
|
||||
{
|
||||
lua_pushnumber(L, CheckLight(L)->GetRadius());
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int Lua_Light_SetRadius(lua_State *L)
|
||||
{
|
||||
CheckLight(L)->SetRadius(static_cast<float>(luaL_checknumber(L, 2)));
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int Lua_Light_GetFalloff(lua_State *L)
|
||||
{
|
||||
lua_pushnumber(L, CheckLight(L)->GetFalloff());
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int Lua_Light_SetFalloff(lua_State *L)
|
||||
{
|
||||
CheckLight(L)->SetFalloff(static_cast<float>(luaL_checknumber(L, 2)));
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int Lua_Light_GetType(lua_State *L)
|
||||
{
|
||||
lua_pushinteger(L, CheckLight(L)->GetType());
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int Lua_Light_SetType(lua_State *L)
|
||||
{
|
||||
CheckLight(L)->SetType(luaL_checkinteger(L, 2));
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int Lua_Light_Index(lua_State *L)
|
||||
{
|
||||
luaL_getmetatable(L, LUA_LIGHT_MT);
|
||||
lua_pushvalue(L, 2);
|
||||
lua_rawget(L, -2);
|
||||
return 1;
|
||||
}
|
||||
|
||||
void RegisterLightType(lua_State *L)
|
||||
{
|
||||
luaL_newmetatable(L, LUA_LIGHT_MT);
|
||||
|
||||
lua_pushcfunction(L, Lua_Light_GetColor); lua_setfield(L, -2, "GetColor");
|
||||
lua_pushcfunction(L, Lua_Light_SetColor); lua_setfield(L, -2, "SetColor");
|
||||
|
||||
lua_pushcfunction(L, Lua_Light_GetIntensity); lua_setfield(L, -2, "GetIntensity");
|
||||
lua_pushcfunction(L, Lua_Light_SetIntensity); lua_setfield(L, -2, "SetIntensity");
|
||||
|
||||
lua_pushcfunction(L, Lua_Light_GetRadius); lua_setfield(L, -2, "GetRadius");
|
||||
lua_pushcfunction(L, Lua_Light_SetRadius); lua_setfield(L, -2, "SetRadius");
|
||||
|
||||
lua_pushcfunction(L, Lua_Light_GetFalloff); lua_setfield(L, -2, "GetFalloff");
|
||||
lua_pushcfunction(L, Lua_Light_SetFalloff); lua_setfield(L, -2, "SetFalloff");
|
||||
|
||||
lua_pushcfunction(L, Lua_Light_GetType); lua_setfield(L, -2, "GetType");
|
||||
lua_pushcfunction(L, Lua_Light_SetType); lua_setfield(L, -2, "SetType");
|
||||
|
||||
lua_pushcfunction(L, Lua_Light_Index);
|
||||
lua_setfield(L, -2, "__index");
|
||||
|
||||
lua_pop(L, 1);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// --- AnimationComponent Lua bindings ---
|
||||
static AnimationComponent *CheckAnimationComponent(lua_State *L, int idx)
|
||||
{
|
||||
@ -347,8 +501,6 @@ static int Lua_Animation_SetEndFrame(lua_State *L)
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static int Lua_Animation_Index(lua_State *L)
|
||||
{
|
||||
// stack: [1]=userdata, [2]=key
|
||||
@ -513,6 +665,102 @@ static int Lua_KeyDown(lua_State *L)
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
static core::types::Vec3 GetLuaVector3(lua_State* L, int index)
|
||||
{
|
||||
if (luaL_testudata(L, index, LUA_VECTOR3_MT))
|
||||
{
|
||||
auto* vec = static_cast<LuaVector3*>(lua_touserdata(L, index));
|
||||
return core::types::Vec3(vec->x, vec->y, vec->z);
|
||||
}
|
||||
else if (lua_istable(L, index))
|
||||
{
|
||||
core::types::Vec3 result;
|
||||
|
||||
static const char* keys1[3] = { "x", "y", "z" };
|
||||
static const char* keys2[3] = { "r", "g", "b" };
|
||||
|
||||
const char** keys = keys1;
|
||||
|
||||
lua_pushstring(L, "x");
|
||||
lua_rawget(L, index);
|
||||
if (lua_isnil(L, -1)) {
|
||||
keys = keys2;
|
||||
lua_pop(L, 1);
|
||||
}
|
||||
|
||||
for (int i = 0; i < 3; ++i)
|
||||
{
|
||||
lua_pushstring(L, keys[i]);
|
||||
lua_rawget(L, index);
|
||||
result[i] = static_cast<float>(lua_tonumber(L, -1));
|
||||
lua_pop(L, 1);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
luaL_error(L, "Expected Vector3 userdata or table with x/y/z or r/g/b");
|
||||
return core::types::Vec3(0, 0, 0);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
static int Lua_Vector3_New(lua_State *L)
|
||||
{
|
||||
PROFILE_DEEP_SCOPE("Vector3()");
|
||||
LuaVector3 *vec = (LuaVector3 *)lua_newuserdata(L, sizeof(LuaVector3));
|
||||
int nargs = lua_gettop(L);
|
||||
vec->x = nargs >= 1 ? static_cast<float>(lua_tonumber(L, 1)) : 0.0f;
|
||||
vec->y = nargs >= 2 ? static_cast<float>(lua_tonumber(L, 2)) : 0.0f;
|
||||
vec->z = nargs >= 3 ? static_cast<float>(lua_tonumber(L, 3)) : 0.0f;
|
||||
luaL_setmetatable(L, LUA_VECTOR3_MT);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int Lua_Vector3_Index(lua_State *L)
|
||||
{
|
||||
auto *vec = (LuaVector3 *)luaL_checkudata(L, 1, LUA_VECTOR3_MT);
|
||||
const char *key = lua_tostring(L, 2);
|
||||
if (!strcmp(key, "x"))
|
||||
lua_pushnumber(L, vec->x);
|
||||
else if (!strcmp(key, "y"))
|
||||
lua_pushnumber(L, vec->y);
|
||||
else if (!strcmp(key, "z"))
|
||||
lua_pushnumber(L, vec->z);
|
||||
else
|
||||
lua_pushnil(L);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int Lua_Vector3_NewIndex(lua_State *L)
|
||||
{
|
||||
auto *vec = (LuaVector3 *)luaL_checkudata(L, 1, LUA_VECTOR3_MT);
|
||||
const char *key = lua_tostring(L, 2);
|
||||
float value = static_cast<float>(luaL_checknumber(L, 3));
|
||||
if (!strcmp(key, "x"))
|
||||
vec->x = value;
|
||||
else if (!strcmp(key, "y"))
|
||||
vec->y = value;
|
||||
else if (!strcmp(key, "z"))
|
||||
vec->z = value;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void RegisterVector3Type(lua_State *L)
|
||||
{
|
||||
luaL_newmetatable(L, LUA_VECTOR3_MT);
|
||||
lua_pushcfunction(L, Lua_Vector3_Index);
|
||||
lua_setfield(L, -2, "__index");
|
||||
lua_pushcfunction(L, Lua_Vector3_NewIndex);
|
||||
lua_setfield(L, -2, "__newindex");
|
||||
lua_pop(L, 1);
|
||||
|
||||
lua_pushcfunction(L, Lua_Vector3_New);
|
||||
lua_setglobal(L, "Vector3");
|
||||
}
|
||||
|
||||
static int Lua_Vector2_New(lua_State *L)
|
||||
{
|
||||
PROFILE_DEEP_SCOPE("Vector2()");
|
||||
@ -632,8 +880,6 @@ void ScriptComponent::RegisterEngineBindings()
|
||||
lua_setfield(L, -2, "GetMousePos");
|
||||
|
||||
lua_setglobal(L, "Engine");
|
||||
|
||||
|
||||
}
|
||||
|
||||
void ScriptComponent::ReloadScript()
|
||||
@ -651,8 +897,10 @@ void ScriptComponent::ReloadScript()
|
||||
|
||||
RegisterObjectType(L);
|
||||
RegisterVector2Type(L);
|
||||
RegisterVector3Type(L);
|
||||
RegisterAnimationType(L);
|
||||
RegisterEngineBindings();
|
||||
RegisterLightType(L);
|
||||
|
||||
keycode_loader(L);
|
||||
|
||||
|
@ -381,7 +381,7 @@ void Engine::ShowDebugOverlay(float deltaTime)
|
||||
float maxFps = *std::max_element(fpsHistory.begin(), fpsHistory.end());
|
||||
maxFps = std::max(maxFps * 1.1f, 60.0f);
|
||||
|
||||
ImGui::PlotLines("##FPS", fpsHistory.data(), fpsHistory.size(), 0, "FPS History",
|
||||
ImGui::PlotLines("##FPS", fpsHistory.data(), fpsHistory.size(), 0, "FPS",
|
||||
0.0f, maxFps, ImVec2(-1, 50));
|
||||
}
|
||||
else
|
||||
@ -537,8 +537,6 @@ void Engine::Init()
|
||||
m_animationsUpdates.reserve(512); // ~500 animated objects (characters, FX, etc.)
|
||||
|
||||
Logger::LogOk("Engine Core");
|
||||
|
||||
|
||||
}
|
||||
|
||||
core::types::Vec2 ScreenToWorld(const core::types::Vec2 &screenPos, const core::types::Vec2 &viewportSize, const core::types::Vec2 &cameraPos, float zoom)
|
||||
@ -563,7 +561,7 @@ void Engine::collectObjects(bool playing, const glm::vec2 &camPos, float camZoom
|
||||
const glm::vec2 screenSize = glm::vec2(Renderer::GetSize());
|
||||
|
||||
for (auto &root : objects)
|
||||
if (!root->GetParent())
|
||||
if (root && !root->GetParent())
|
||||
m_collectStack.push_back(root);
|
||||
|
||||
while (!m_collectStack.empty())
|
||||
@ -820,7 +818,7 @@ void Engine::Run()
|
||||
}
|
||||
|
||||
for (auto &obj : objects)
|
||||
if (!obj->GetParent())
|
||||
if (obj && !obj->GetParent())
|
||||
DrawObjectNode(obj);
|
||||
|
||||
ImGui::End();
|
||||
@ -1152,26 +1150,51 @@ void Engine::Run()
|
||||
}
|
||||
}
|
||||
|
||||
if (ImGui::BeginDragDropTarget())
|
||||
{
|
||||
if (const ImGuiPayload *payload = ImGui::AcceptDragDropPayload("ASSET_TEXTURE"))
|
||||
{
|
||||
if (payload->DataSize == sizeof(uint64_t))
|
||||
static std::shared_ptr<Object> previewObj = nullptr;
|
||||
static uint64_t previewUAID = 0;
|
||||
|
||||
const ImGuiPayload *payload = ImGui::GetDragDropPayload();
|
||||
bool draggingTexture = payload && payload->IsDataType("ASSET_TEXTURE") && payload->DataSize == sizeof(uint64_t);
|
||||
bool mouseHeld = ImGui::IsMouseDown(ImGuiMouseButton_Left);
|
||||
bool mouseReleased = ImGui::IsMouseReleased(ImGuiMouseButton_Left);
|
||||
bool hoveringViewport = ImGui::IsWindowHovered(ImGuiHoveredFlags_AllowWhenBlockedByActiveItem);
|
||||
|
||||
// While dragging and hovering viewport
|
||||
if (draggingTexture && mouseHeld && hoveringViewport)
|
||||
{
|
||||
uint64_t uaid = *(const uint64_t *)payload->Data;
|
||||
const auto *asset = AssetManager::GetAssetByID(uaid);
|
||||
if (asset && asset->type == AssetType::Image)
|
||||
{
|
||||
if (!previewObj)
|
||||
{
|
||||
previewObj = std::make_shared<Object>(asset->filename);
|
||||
previewObj->AddComponent<SpriteComponent>()->SetTexture(uaid);
|
||||
objects.push_back(previewObj);
|
||||
previewUAID = uaid;
|
||||
}
|
||||
|
||||
glm::vec2 worldPos = ScreenToWorld(screenMousePos, viewportSize, cameraPos, cameraZoom);
|
||||
|
||||
auto obj = std::make_shared<Object>("New Sprite");
|
||||
obj->SetLocalPosition(worldPos);
|
||||
|
||||
auto sprite = obj->AddComponent<SpriteComponent>();
|
||||
sprite->SetTexture(uaid);
|
||||
|
||||
objects.push_back(obj);
|
||||
previewObj->SetLocalPosition(worldPos);
|
||||
selected = previewObj;
|
||||
}
|
||||
}
|
||||
ImGui::EndDragDropTarget();
|
||||
else if (previewObj && mouseReleased && hoveringViewport)
|
||||
{
|
||||
|
||||
previewObj = nullptr;
|
||||
previewUAID = 0;
|
||||
}
|
||||
else if (previewObj && (!hoveringViewport || !draggingTexture))
|
||||
{
|
||||
auto it = std::find(objects.begin(), objects.end(), previewObj);
|
||||
if (it != objects.end())
|
||||
objects.erase(it);
|
||||
|
||||
previewObj = nullptr;
|
||||
selected = previewObj;
|
||||
|
||||
previewUAID = 0;
|
||||
}
|
||||
|
||||
ImGui::End();
|
||||
@ -1229,10 +1252,14 @@ void Engine::Run()
|
||||
|
||||
void Engine::DrawObjectNode(const std::shared_ptr<Object>& obj)
|
||||
{
|
||||
if (!obj)
|
||||
return;
|
||||
|
||||
PROFILE_ENGINE_SCOPE("Engine::DrawObjectNode");
|
||||
|
||||
ImGuiTreeNodeFlags flags = ImGuiTreeNodeFlags_OpenOnArrow |
|
||||
ImGuiTreeNodeFlags_SpanAvailWidth |
|
||||
ImGuiTreeNodeFlags_DefaultOpen |
|
||||
(obj == selected ? ImGuiTreeNodeFlags_Selected : 0);
|
||||
|
||||
bool open = ImGui::TreeNodeEx((void*)(intptr_t)obj->uid.id, flags, "%s", obj->GetName().c_str());
|
||||
@ -1240,13 +1267,10 @@ void Engine::DrawObjectNode(const std::shared_ptr<Object> &obj)
|
||||
if (ImGui::IsItemClicked())
|
||||
selected = obj;
|
||||
|
||||
// === Context Menu ===
|
||||
if (ImGui::BeginPopupContextItem())
|
||||
{
|
||||
if (ImGui::MenuItem("Delete"))
|
||||
{
|
||||
pendingDeletion.push_back(obj);
|
||||
}
|
||||
if (ImGui::MenuItem("Create Child"))
|
||||
{
|
||||
auto child = std::make_shared<Object>("NewObject");
|
||||
@ -1257,58 +1281,59 @@ void Engine::DrawObjectNode(const std::shared_ptr<Object> &obj)
|
||||
ImGui::EndPopup();
|
||||
}
|
||||
|
||||
// === Drag Source ===
|
||||
if (ImGui::BeginDragDropSource())
|
||||
{
|
||||
ImGui::SetDragDropPayload("OBJECT", &obj, sizeof(obj));
|
||||
ImGui::Text("Move: %s", obj->GetName().c_str());
|
||||
auto dragRef = obj;
|
||||
ImGui::SetDragDropPayload("OBJECT", &dragRef, sizeof(dragRef));
|
||||
ImGui::Text("%s", obj->GetName().c_str());
|
||||
ImGui::EndDragDropSource();
|
||||
}
|
||||
|
||||
// === Drop Target ===
|
||||
if (ImGui::BeginDragDropTarget())
|
||||
{
|
||||
if (const ImGuiPayload *payload = ImGui::AcceptDragDropPayload("OBJECT"))
|
||||
if (auto payload = ImGui::AcceptDragDropPayload("OBJECT"))
|
||||
{
|
||||
auto dragged = *(std::shared_ptr<Object> *)payload->Data;
|
||||
auto dragged = *static_cast<std::shared_ptr<Object>*>(payload->Data);
|
||||
|
||||
if (dragged != obj && dragged)
|
||||
if (dragged && dragged != obj)
|
||||
{
|
||||
Object *oldParent = dragged->GetParent();
|
||||
|
||||
if (oldParent)
|
||||
bool valid = true;
|
||||
for (Object* a = obj.get(); a; a = a->GetParent())
|
||||
if (a == dragged.get())
|
||||
{
|
||||
oldParent->RemoveChild(dragged.get());
|
||||
|
||||
for (const auto &candidate : objects)
|
||||
{
|
||||
if (candidate.get() == oldParent)
|
||||
{
|
||||
pendingDeletion.push_back(candidate);
|
||||
valid = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
|
||||
if (valid)
|
||||
{
|
||||
if (auto oldP = dragged->GetParent())
|
||||
oldP->RemoveChild(dragged.get());
|
||||
else
|
||||
objects.erase(std::remove(objects.begin(), objects.end(), dragged), objects.end());
|
||||
}
|
||||
|
||||
|
||||
obj->AddChild(dragged);
|
||||
dragged->SetWorldPosition(
|
||||
dragged->GetWorldPosition() - obj->GetWorldPosition()
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
ImGui::EndDragDropTarget();
|
||||
}
|
||||
|
||||
// === Children ===
|
||||
if (open)
|
||||
{
|
||||
for (auto& child : obj->GetChildren())
|
||||
if (child)
|
||||
DrawObjectNode(child);
|
||||
ImGui::TreePop();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
bool VerifySceneHash(const YAML::Node &root)
|
||||
{
|
||||
if (!root["scene_hash"] || !root["objects"])
|
||||
@ -1422,6 +1447,7 @@ void Engine::LoadScene(const std::string &path)
|
||||
loadingUI.Update(currentStep, currentDetail, 0.1f);
|
||||
|
||||
objects.clear();
|
||||
Object::usedIDs.clear();
|
||||
|
||||
Logger::LogDebug("[LoadScene] Recreating Objects");
|
||||
currentStep = "Creating Scene Objects";
|
||||
|
@ -10,16 +10,35 @@
|
||||
#include "../Components/AnimationComponent.h"
|
||||
#include "../Components/AudioPlayerComponent.h"
|
||||
|
||||
|
||||
#include "../core/utils/Logging.h"
|
||||
#include "../utils/UID.h"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
Object::Object(const std::string &name)
|
||||
: name(name), localPosition(0.0f, 0.0f), localRotationDeg(0.0f), uid(), visable(true) {}
|
||||
static constexpr float PI = 3.14159265358979323846f;
|
||||
|
||||
|
||||
std::unordered_set<int> Object::usedIDs;
|
||||
|
||||
Object::Object(const std::string& name)
|
||||
: name(name), localPosition(0.0f, 0.0f), localRotationDeg(0.0f), uid(), visable(true)
|
||||
{
|
||||
if (usedIDs.count(uid.id))
|
||||
{
|
||||
Logger::LogWarning("Constructor: Duplicate ID %d detected. Assigning a new ID.", uid.id);
|
||||
uid.id = GetNextAvailableID();
|
||||
}
|
||||
usedIDs.insert(uid.id);
|
||||
parent = nullptr;
|
||||
}
|
||||
|
||||
|
||||
|
||||
Object::~Object()
|
||||
{
|
||||
usedIDs.erase(uid.id);
|
||||
}
|
||||
|
||||
Object::~Object() {}
|
||||
|
||||
void Object::SetParent(Object *newParent)
|
||||
{
|
||||
@ -65,6 +84,30 @@ glm::vec2 Object::GetWorldPosition() const
|
||||
return localPosition;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void Object::SetWorldPosition(const core::types::Vec2& worldPos) {
|
||||
if (Object* parent = GetParent()) {
|
||||
core::types::Vec2 parentPos = parent->GetWorldPosition();
|
||||
core::types::Vec2 offset = worldPos - parentPos;
|
||||
|
||||
float parentDeg = parent->GetWorldRotation();
|
||||
float rad = -parentDeg * (PI / 180.0f);
|
||||
float c = std::cos(rad);
|
||||
float s = std::sin(rad);
|
||||
|
||||
core::types::Vec2 local{
|
||||
offset.x * c - offset.y * s,
|
||||
offset.x * s + offset.y * c
|
||||
};
|
||||
|
||||
SetLocalPosition(local);
|
||||
}
|
||||
else {
|
||||
SetLocalPosition(worldPos);
|
||||
}
|
||||
}
|
||||
|
||||
float Object::GetLocalRotation() const
|
||||
{
|
||||
return localRotationDeg;
|
||||
@ -75,6 +118,13 @@ void Object::SetLocalRotation(float deg)
|
||||
localRotationDeg = deg;
|
||||
}
|
||||
|
||||
float Object::GetWorldScale() const
|
||||
{
|
||||
return 1.0f;
|
||||
}
|
||||
|
||||
|
||||
|
||||
float Object::GetWorldRotation() const
|
||||
{
|
||||
if (parent)
|
||||
@ -95,7 +145,16 @@ void Object::SetVisable(bool state)
|
||||
const std::string &Object::GetName() const { return name; }
|
||||
void Object::SetName(const std::string &n) { name = n; }
|
||||
std::vector<std::shared_ptr<Object>> &Object::GetChildren() { return children; }
|
||||
Object *Object::GetParent() const { return parent; }
|
||||
Object* Object::GetParent() const
|
||||
{
|
||||
if (!this)
|
||||
{
|
||||
Logger::LogError("Object::GetParent() called on nullptr");
|
||||
return nullptr;
|
||||
}
|
||||
return parent;
|
||||
}
|
||||
|
||||
|
||||
void Object::Save(YAML::Emitter &out) const
|
||||
{
|
||||
@ -128,9 +187,11 @@ void Object::Save(YAML::Emitter &out) const
|
||||
|
||||
void Object::Load(const YAML::Node &node)
|
||||
{
|
||||
|
||||
|
||||
name = node["name"].as<std::string>();
|
||||
uid.uuid = node["uid"] ? node["uid"].as<std::string>() : GenerateUUID();
|
||||
uid.id = node["id"] ? node["id"].as<int>() : 0;
|
||||
int loadedID = node["id"] ? node["id"].as<int>() : 0;
|
||||
|
||||
auto pos = node["position"];
|
||||
if (pos && pos.IsSequence() && pos.size() == 2)
|
||||
|
@ -9,6 +9,13 @@
|
||||
|
||||
#include <yaml-cpp/yaml.h>
|
||||
#include "../utils/UID.h"
|
||||
#include <unordered_set>
|
||||
|
||||
#include "../core/types/all.h"
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
class Component;
|
||||
|
||||
@ -28,6 +35,10 @@ public:
|
||||
float GetLocalRotation() const;
|
||||
void SetLocalRotation(float deg);
|
||||
float GetWorldRotation() const;
|
||||
void SetWorldPosition(const core::types::Vec2& worldPos);
|
||||
|
||||
float GetWorldScale() const;
|
||||
|
||||
|
||||
void SetParent(Object *parent);
|
||||
Object *GetParent() const;
|
||||
@ -51,6 +62,9 @@ public:
|
||||
UID uid;
|
||||
int layer = 0;
|
||||
|
||||
static std::unordered_set<int> usedIDs;
|
||||
|
||||
|
||||
private:
|
||||
bool visable = true;
|
||||
std::string name;
|
||||
@ -59,6 +73,15 @@ private:
|
||||
Object *parent = nullptr;
|
||||
std::vector<std::shared_ptr<Object>> children;
|
||||
std::vector<std::shared_ptr<Component>> components;
|
||||
|
||||
|
||||
static int GetNextAvailableID()
|
||||
{
|
||||
static int nextID = 1;
|
||||
while (usedIDs.count(nextID))
|
||||
++nextID;
|
||||
return nextID;
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
|
@ -26,6 +26,7 @@ static Shader tilemapShader;
|
||||
static Shader extractShader;
|
||||
static Shader blurShader;
|
||||
static Shader compositeShader;
|
||||
static Shader s_OutlineShader;
|
||||
|
||||
static GLuint extractFBO, extractTexture;
|
||||
static GLuint blurFBO_H, blurTexture_H;
|
||||
@ -195,9 +196,9 @@ void Renderer::InitQuadBatch()
|
||||
|
||||
void Renderer::Init()
|
||||
{
|
||||
|
||||
Logger::LogVerbose("[Renderer] Create Primary");
|
||||
|
||||
// Main framebuffer
|
||||
glGenFramebuffers(1, &fbo);
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, fbo);
|
||||
|
||||
@ -220,10 +221,7 @@ void Renderer::Init()
|
||||
|
||||
InitQuad();
|
||||
|
||||
// Load lit shader
|
||||
|
||||
// Core renderers
|
||||
{
|
||||
// Load shaders
|
||||
spriteShader.LoadFromFile("src/assets/shaders/sprite.vert", "src/assets/shaders/sprite.frag");
|
||||
unlitShader.LoadFromFile("src/assets/shaders/unlit.vert", "src/assets/shaders/unlit.frag");
|
||||
tilemapShader.LoadFromFile("src/assets/shaders/tilemap.vert", "src/assets/shaders/tilemap.frag");
|
||||
@ -234,27 +232,23 @@ void Renderer::Init()
|
||||
compositeShader.LoadFromFile("src/assets/shaders/fullscreen.vert", "src/assets/shaders/composite.frag");
|
||||
|
||||
s_UnlitQuadShader.LoadFromFile("src/assets/shaders/unlit_quad.vert", "src/assets/shaders/unlit_quad.frag");
|
||||
|
||||
|
||||
s_OutlineShader.LoadFromFile("src/assets/shaders/outline.vert", "src/assets/shaders/outline.frag");
|
||||
|
||||
Logger::LogOk("Shader Core");
|
||||
}
|
||||
|
||||
InitQuadBatch();
|
||||
|
||||
Logger::LogVerbose("[Renderer] Color Correction Init");
|
||||
|
||||
SetColorCorrection(std::make_unique<ColorCorrection>());
|
||||
|
||||
{
|
||||
Logger::LogVerbose("Renderer::InitLightUniforms(%d)", g_engineConfig.gl_maxLight);
|
||||
InitLightUniforms(g_engineConfig.gl_maxLight);
|
||||
}
|
||||
|
||||
glGenBuffers(1, &s_ClusterSSBO);
|
||||
|
||||
Logger::LogVerbose("[Renderer] Bloom Init");
|
||||
|
||||
// Bloom extract
|
||||
glGenFramebuffers(1, &extractFBO);
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, extractFBO);
|
||||
glGenTextures(1, &extractTexture);
|
||||
@ -264,6 +258,7 @@ void Renderer::Init()
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, extractTexture, 0);
|
||||
|
||||
// Horizontal blur
|
||||
glGenFramebuffers(1, &blurFBO_H);
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, blurFBO_H);
|
||||
glGenTextures(1, &blurTexture_H);
|
||||
@ -273,6 +268,7 @@ void Renderer::Init()
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, blurTexture_H, 0);
|
||||
|
||||
// Vertical blur
|
||||
glGenFramebuffers(1, &blurFBO_V);
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, blurFBO_V);
|
||||
glGenTextures(1, &blurTexture_V);
|
||||
@ -282,7 +278,7 @@ void Renderer::Init()
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, blurTexture_V, 0);
|
||||
|
||||
// Final composite target
|
||||
// Final bloom composite
|
||||
glGenFramebuffers(1, &bloomFBO);
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, bloomFBO);
|
||||
glGenTextures(1, &bloomTexture);
|
||||
@ -513,6 +509,7 @@ void Renderer::DrawTilemap(TilemapComponent *tilemap,
|
||||
int gx, gy;
|
||||
TilemapComponent::UnpackCoord(key, gx, gy);
|
||||
|
||||
|
||||
// world→screen position
|
||||
glm::vec2 worldPos = {gx * tileSize.x, gy * tileSize.y};
|
||||
glm::vec2 screenPos = (worldPos - cameraPos) * zoom + screenCenter;
|
||||
@ -520,8 +517,9 @@ void Renderer::DrawTilemap(TilemapComponent *tilemap,
|
||||
// quad size in screen‐space
|
||||
glm::vec2 finalSize = tileSize * zoom;
|
||||
|
||||
// fetch UVs (already handles flipping for you)
|
||||
auto uvRect = atlas->GetFrameUVRect(tileIndex);
|
||||
|
||||
const core::types::Vec2 uvMin = atlas->GetFrameUV(tileIndex);
|
||||
const core::types::Vec2 uvMax = uvMin + atlas->GetFrameSizeUV();
|
||||
|
||||
// batch that sprite
|
||||
BatchedSprite entry{};
|
||||
@ -533,8 +531,8 @@ void Renderer::DrawTilemap(TilemapComponent *tilemap,
|
||||
entry.renderType = RenderType::Unlit;
|
||||
entry.sprite = nullptr;
|
||||
entry.texCoords = glm::vec4(
|
||||
uvRect.min.x, uvRect.min.y,
|
||||
uvRect.max.x, uvRect.max.y);
|
||||
uvMin.x, uvMin.y,
|
||||
uvMax.x, uvMax.y);
|
||||
|
||||
SortedDrawEntry drawEntry{};
|
||||
drawEntry.sprite = entry;
|
||||
|
@ -22,7 +22,7 @@ struct ColorCorrection
|
||||
float saturation = 1.0f;
|
||||
float gamma = 1.0f;
|
||||
|
||||
bool bloom = true;
|
||||
bool bloom = false;
|
||||
float threshold = 1.0f;
|
||||
float intensity = 1.2f;
|
||||
|
||||
@ -54,6 +54,11 @@ struct QuadInstance
|
||||
class Renderer
|
||||
{
|
||||
public:
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
static void Init();
|
||||
static void Resize(int w, int h);
|
||||
static void Begin();
|
||||
@ -62,7 +67,6 @@ public:
|
||||
static void DrawSprite(SpriteComponent *sprite, const glm::vec2 &pos, float zoom, glm::vec2 &CameraPos);
|
||||
static void DrawTilemap(TilemapComponent *tilemap, const glm::vec2 &pos, float zoom, const glm::vec2 &cameraPos);
|
||||
|
||||
|
||||
static void AddLight(const glm::vec2 &screenPos, const glm::vec3 &color, float intensity, float radius);
|
||||
static void ClearLights();
|
||||
|
||||
@ -105,6 +109,7 @@ public:
|
||||
|
||||
static void FlushQuads();
|
||||
|
||||
|
||||
private:
|
||||
static std::vector<Light> s_Lights;
|
||||
|
||||
@ -119,10 +124,11 @@ private:
|
||||
static GLuint LoadShader(const char *vertexSrc, const char *fragmentSrc);
|
||||
static std::unique_ptr<ColorCorrection> s_ColorCorrection;
|
||||
|
||||
// Clustered Lighting
|
||||
|
||||
static constexpr int CLUSTER_SIZE = 16;
|
||||
static constexpr int MAX_LIGHTS_PER_CLUSTER = 32;
|
||||
|
||||
|
||||
struct Cluster
|
||||
{
|
||||
std::vector<int> lightIndices;
|
||||
@ -143,4 +149,5 @@ private:
|
||||
|
||||
static void *s_QuadMappedPtr;
|
||||
static GLuint s_QuadPersistentFlags;
|
||||
|
||||
};
|
||||
|
@ -157,20 +157,14 @@ void AudioEngine::SetVolume(uint64_t uaid, float v) {
|
||||
if (auto it = s_SoundMap.find(uaid); it != s_SoundMap.end()) {
|
||||
ma_sound_set_volume(it->second, v);
|
||||
}
|
||||
else
|
||||
{
|
||||
Logger::LogError("[AudioEngine] Invalid Asset ID");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void AudioEngine::SetLooping(uint64_t uaid, bool loop) {
|
||||
if (auto it = s_SoundMap.find(uaid); it != s_SoundMap.end()) {
|
||||
ma_sound_set_looping(it->second, loop ? MA_TRUE : MA_FALSE);
|
||||
}
|
||||
else
|
||||
{
|
||||
Logger::LogError("[AudioEngine] Invalid Asset ID");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void AudioEngine::Cleanup(uint64_t uaid) {
|
||||
|
@ -27,6 +27,8 @@ namespace core
|
||||
|
||||
Vec3 operator*(const Vec3 &rhs) const { return {x * rhs.x, y * rhs.y, z * rhs.z}; }
|
||||
|
||||
|
||||
|
||||
Vec3 &operator+=(const Vec3 &rhs) { x += rhs.x; y += rhs.y; z += rhs.z; return *this; }
|
||||
Vec3 &operator-=(const Vec3 &rhs) { x -= rhs.x; y -= rhs.y; z -= rhs.z; return *this; }
|
||||
Vec3 &operator*=(float scalar) { x *= scalar; y *= scalar; z *= scalar; return *this; }
|
||||
@ -89,9 +91,29 @@ namespace core
|
||||
{
|
||||
return os << "(" << v.x << ", " << v.y << ", " << v.z << ")";
|
||||
}
|
||||
|
||||
inline float& operator[](int i) {
|
||||
switch (i) {
|
||||
case 0: return x;
|
||||
case 1: return y;
|
||||
case 2: return z;
|
||||
default: throw std::out_of_range("Vec3 index out of range");
|
||||
}
|
||||
}
|
||||
|
||||
inline const float& operator[](int i) const {
|
||||
switch (i) {
|
||||
case 0: return x;
|
||||
case 1: return y;
|
||||
case 2: return z;
|
||||
default: throw std::out_of_range("Vec3 index out of range");
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
inline Vec3 operator*(float scalar, const Vec3 &v) { return v * scalar; }
|
||||
|
||||
|
||||
|
||||
} // namespace types
|
||||
} // namespace core
|
||||
|
@ -3,6 +3,7 @@
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
#include "../audio/AudioEngine.h"
|
||||
#include "LoadingWindow.h"
|
||||
#define STB_IMAGE_IMPLEMENTATION
|
||||
#include <stb_image.h>
|
||||
|
||||
@ -368,8 +369,18 @@ void AssetManager::Load(const YAML::Node &node)
|
||||
if (!node)
|
||||
return;
|
||||
|
||||
|
||||
LoadingWindow loadingUI;
|
||||
loadingUI.Create("Loading Assets");
|
||||
|
||||
const size_t total = node.size();
|
||||
size_t index = 0;
|
||||
|
||||
|
||||
|
||||
for (const auto &item : node)
|
||||
{
|
||||
|
||||
uint64_t uaid = item["uaid"].as<uint64_t>();
|
||||
std::string path = item["path"].as<std::string>();
|
||||
AssetType type = static_cast<AssetType>(item["type"].as<int>());
|
||||
@ -382,6 +393,9 @@ void AssetManager::Load(const YAML::Node &node)
|
||||
else
|
||||
continue;
|
||||
|
||||
float progress = static_cast<float>(index) / total;
|
||||
loadingUI.Update("Loading Asset", path, progress);
|
||||
|
||||
asset->uaid = uaid;
|
||||
asset->path = path;
|
||||
asset->filename = item["filename"] ? item["filename"].as<std::string>() : GetFilenameFromPath(path);
|
||||
@ -402,7 +416,11 @@ void AssetManager::Load(const YAML::Node &node)
|
||||
LoadImageInternal(path, uaid);
|
||||
else if (type == AssetType::Audio)
|
||||
LoadAudioInternal(path, uaid);
|
||||
|
||||
++index;
|
||||
|
||||
}
|
||||
loadingUI.Destroy();
|
||||
}
|
||||
|
||||
void ImageAssetInfo::Save(YAML::Emitter &out) const
|
||||
|
@ -9,7 +9,7 @@
|
||||
#include <GL/glew.h>
|
||||
#include "miniaudio.h"
|
||||
|
||||
enum class AssetType { Image, Audio };
|
||||
enum class AssetType { Image, Audio, Unknown };
|
||||
|
||||
struct AssetInfo
|
||||
{
|
||||
|
@ -7,8 +7,11 @@
|
||||
#include <string>
|
||||
#include <filesystem>
|
||||
#include "FileDialog.h"
|
||||
#include <vector>
|
||||
|
||||
|
||||
//TODO: Make this all memroy safe.
|
||||
|
||||
// Correctly null-terminated filter strings
|
||||
static std::unordered_map<FileDialogType, const char*> filters = {
|
||||
{ FileDialogType::Images, "Image Files\0*.png;*.jpg;*.jpeg;*.bmp;*.tga;*.gif;*.dds\0All Files\0*.*\0" },
|
||||
{ FileDialogType::Scenes, "CreateScene Files\0*.cene;*.cscene;*.yaml\0All Files\0*.*\0" },
|
||||
@ -101,3 +104,44 @@ std::string CreateFileDialog(FileDialogType type) {
|
||||
return "";
|
||||
}
|
||||
|
||||
|
||||
|
||||
std::vector<std::string> OpenMultipleFilesDialog(FileDialogType type) {
|
||||
const size_t bufferSize = 32768;
|
||||
std::vector<char> fileBuffer(bufferSize, 0);
|
||||
|
||||
OPENFILENAMEA ofn = {};
|
||||
ofn.lStructSize = sizeof(ofn);
|
||||
|
||||
const char* filterStr = filters.count(type) ? filters[type] : filters[FileDialogType::All];
|
||||
ofn.lpstrFilter = filterStr;
|
||||
ofn.lpstrFile = fileBuffer.data();
|
||||
ofn.nMaxFile = static_cast<DWORD>(fileBuffer.size());
|
||||
ofn.Flags = OFN_FILEMUSTEXIST | OFN_HIDEREADONLY |
|
||||
OFN_NOCHANGEDIR | OFN_ALLOWMULTISELECT | OFN_EXPLORER;
|
||||
|
||||
auto originalPath = std::filesystem::current_path();
|
||||
bool result = GetOpenFileNameA(&ofn);
|
||||
std::filesystem::current_path(originalPath);
|
||||
|
||||
std::vector<std::string> selectedFiles;
|
||||
|
||||
if (!result || fileBuffer[0] == '\0')
|
||||
return selectedFiles;
|
||||
|
||||
std::string directory(fileBuffer.data());
|
||||
char* p = fileBuffer.data() + directory.size() + 1;
|
||||
|
||||
if (*p == '\0') {
|
||||
selectedFiles.push_back(directory);
|
||||
} else {
|
||||
while (*p != '\0') {
|
||||
std::string filename(p);
|
||||
std::filesystem::path fullPath = std::filesystem::path(directory) / filename;
|
||||
selectedFiles.push_back(fullPath.string());
|
||||
p += filename.size() + 1;
|
||||
}
|
||||
}
|
||||
|
||||
return selectedFiles;
|
||||
}
|
||||
|
@ -1,5 +1,7 @@
|
||||
#pragma once
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
|
||||
enum class FileDialogType {
|
||||
Images,
|
||||
@ -16,4 +18,6 @@ enum class FileDialogType {
|
||||
std::string OpenFileDialog(FileDialogType type);
|
||||
std::string SaveFileDialog(FileDialogType type);
|
||||
std::string CreateFileDialog(FileDialogType type);
|
||||
std::vector<std::string> OpenMultipleFilesDialog(FileDialogType type);
|
||||
|
||||
|
||||
|
@ -4,25 +4,29 @@
|
||||
#include <algorithm>
|
||||
|
||||
static const wchar_t* kWindowClass = L"LoadingWndClass";
|
||||
static LoadingWindow* g_instance = nullptr;
|
||||
|
||||
void LoadingWindow::Create(const std::string& title)
|
||||
{
|
||||
g_instance = this;
|
||||
windowTitle = std::wstring(title.begin(), title.end());
|
||||
|
||||
// Register the window class (once)
|
||||
static bool registered = false;
|
||||
if (!registered)
|
||||
{
|
||||
WNDCLASS wc = {};
|
||||
wc.lpfnWndProc = WndProc;
|
||||
wc.lpfnWndProc = LoadingWindow::ThunkProc;
|
||||
wc.hInstance = GetModuleHandle(nullptr);
|
||||
wc.lpszClassName = kWindowClass;
|
||||
wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
|
||||
RegisterClass(&wc);
|
||||
registered = true;
|
||||
}
|
||||
|
||||
hwnd = CreateWindowEx(
|
||||
0, kWindowClass, windowTitle.c_str(),
|
||||
WS_OVERLAPPEDWINDOW & ~WS_MAXIMIZEBOX & ~WS_THICKFRAME,
|
||||
CW_USEDEFAULT, CW_USEDEFAULT, 500, 200,
|
||||
nullptr, nullptr, GetModuleHandle(nullptr), nullptr
|
||||
nullptr, nullptr, GetModuleHandle(nullptr), this
|
||||
);
|
||||
|
||||
ShowWindow(hwnd, SW_SHOWNORMAL);
|
||||
@ -53,12 +57,28 @@ void LoadingWindow::Destroy()
|
||||
DestroyWindow(hwnd);
|
||||
hwnd = nullptr;
|
||||
}
|
||||
UnregisterClass(kWindowClass, GetModuleHandle(nullptr));
|
||||
}
|
||||
|
||||
LRESULT CALLBACK LoadingWindow::WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
|
||||
LRESULT CALLBACK LoadingWindow::ThunkProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
|
||||
{
|
||||
if (msg == WM_PAINT && g_instance)
|
||||
if (msg == WM_NCCREATE)
|
||||
{
|
||||
// Store 'this' in GWLP_USERDATA
|
||||
CREATESTRUCT* cs = reinterpret_cast<CREATESTRUCT*>(lParam);
|
||||
SetWindowLongPtr(hWnd, GWLP_USERDATA, reinterpret_cast<LONG_PTR>(cs->lpCreateParams));
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
LoadingWindow* self = reinterpret_cast<LoadingWindow*>(GetWindowLongPtr(hWnd, GWLP_USERDATA));
|
||||
if (self)
|
||||
return self->WndProc(hWnd, msg, wParam, lParam);
|
||||
|
||||
return DefWindowProc(hWnd, msg, wParam, lParam);
|
||||
}
|
||||
|
||||
LRESULT LoadingWindow::WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
|
||||
{
|
||||
if (msg == WM_PAINT)
|
||||
{
|
||||
PAINTSTRUCT ps;
|
||||
HDC hdc = BeginPaint(hWnd, &ps);
|
||||
@ -66,8 +86,8 @@ LRESULT CALLBACK LoadingWindow::WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPAR
|
||||
RECT r;
|
||||
GetClientRect(hWnd, &r);
|
||||
|
||||
std::wstring step = std::wstring(g_instance->currentStep.begin(), g_instance->currentStep.end());
|
||||
std::wstring detail = std::wstring(g_instance->currentDetail.begin(), g_instance->currentDetail.end());
|
||||
std::wstring step = std::wstring(currentStep.begin(), currentStep.end());
|
||||
std::wstring detail = std::wstring(currentDetail.begin(), currentDetail.end());
|
||||
|
||||
SetBkMode(hdc, TRANSPARENT);
|
||||
SelectObject(hdc, GetStockObject(DEFAULT_GUI_FONT));
|
||||
@ -87,7 +107,7 @@ LRESULT CALLBACK LoadingWindow::WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPAR
|
||||
DeleteObject(bg);
|
||||
|
||||
// Progress bar fill
|
||||
int barWidth = static_cast<int>((progressRect.right - progressRect.left) * g_instance->currentProgress);
|
||||
int barWidth = static_cast<int>((progressRect.right - progressRect.left) * currentProgress);
|
||||
RECT fillRect = { progressRect.left, progressRect.top, progressRect.left + barWidth, progressRect.bottom };
|
||||
HBRUSH fill = CreateSolidBrush(RGB(70, 140, 255));
|
||||
FillRect(hdc, &fillRect, fill);
|
||||
|
@ -5,7 +5,7 @@
|
||||
class LoadingWindow {
|
||||
public:
|
||||
void Create(const std::string& title = "Loading...");
|
||||
void Update(const std::string& step, const std::string& detail, float progress); // NEW
|
||||
void Update(const std::string& step, const std::string& detail, float progress);
|
||||
void Destroy();
|
||||
|
||||
private:
|
||||
@ -15,5 +15,9 @@ private:
|
||||
std::string currentDetail;
|
||||
float currentProgress = 0.0f;
|
||||
|
||||
static LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);
|
||||
// Static thunk to route Windows messages to the correct instance
|
||||
static LRESULT CALLBACK ThunkProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);
|
||||
|
||||
// Actual message handler for this instance
|
||||
LRESULT WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);
|
||||
};
|
||||
|
@ -5,8 +5,13 @@
|
||||
#include "../../core/utils/AssetManager.h"
|
||||
#include "../../Renderer.h"
|
||||
#include "../../core/utils/Logging.h"
|
||||
#include "../../core/utils/LoadingWindow.h"
|
||||
|
||||
static std::string assetSearchQuery;
|
||||
static bool sortAscending = true;
|
||||
static int sortMode = 0; // 0 = Name, 1 = Type, 2 = UAID
|
||||
static bool showImages = true;
|
||||
static bool showAudio = true;
|
||||
|
||||
void ShowAssetBrowser()
|
||||
{
|
||||
@ -15,33 +20,95 @@ void ShowAssetBrowser()
|
||||
if (!g_engineConfig.settings.show_asset_window)
|
||||
return;
|
||||
|
||||
ImGui::Begin("Asset Browser");
|
||||
ImGui::Begin("Resources");
|
||||
|
||||
if (ImGui::Button("Load Image"))
|
||||
// Top bar layout
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(6, 4));
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(8, 6));
|
||||
|
||||
// Load Buttons
|
||||
if (ImGui::Button("Load Images"))
|
||||
{
|
||||
std::string path = OpenFileDialog(FileDialogType::Images);
|
||||
if (!path.empty())
|
||||
std::vector<std::string> paths = OpenMultipleFilesDialog(FileDialogType::Images);
|
||||
if (!paths.empty())
|
||||
{
|
||||
LoadingWindow loader;
|
||||
loader.Create("Loading Images...");
|
||||
|
||||
for (size_t i = 0; i < paths.size(); ++i)
|
||||
{
|
||||
const std::string &path = paths[i];
|
||||
loader.Update("Loading Image", path, static_cast<float>(i + 1) / paths.size());
|
||||
AssetManager::LoadAssetAsync(path, AssetType::Image);
|
||||
}
|
||||
|
||||
loader.Destroy();
|
||||
}
|
||||
}
|
||||
|
||||
ImGui::SameLine();
|
||||
|
||||
if (ImGui::Button("Load Audio"))
|
||||
{
|
||||
std::string path = OpenFileDialog(FileDialogType::Audio);
|
||||
if (!path.empty())
|
||||
std::vector<std::string> paths = OpenMultipleFilesDialog(FileDialogType::Audio);
|
||||
if (!paths.empty())
|
||||
{
|
||||
LoadingWindow loader;
|
||||
loader.Create("Loading Audio...");
|
||||
|
||||
for (size_t i = 0; i < paths.size(); ++i)
|
||||
{
|
||||
const std::string &path = paths[i];
|
||||
loader.Update("Loading Audio", path, static_cast<float>(i + 1) / paths.size());
|
||||
AssetManager::LoadAssetAsync(path, AssetType::Audio);
|
||||
}
|
||||
|
||||
loader.Destroy();
|
||||
}
|
||||
}
|
||||
|
||||
ImGui::SameLine();
|
||||
|
||||
if (ImGui::Button("Filters / Sort"))
|
||||
ImGui::OpenPopup("AssetBrowserFilterPopup");
|
||||
|
||||
// Filters Popup
|
||||
if (ImGui::BeginPopup("AssetBrowserFilterPopup"))
|
||||
{
|
||||
ImGui::Text("Sort By:");
|
||||
if (ImGui::Selectable("Name", sortMode == 0))
|
||||
sortMode = 0;
|
||||
if (ImGui::Selectable("Type", sortMode == 1))
|
||||
sortMode = 1;
|
||||
if (ImGui::Selectable("UAID", sortMode == 2))
|
||||
sortMode = 2;
|
||||
|
||||
ImGui::Checkbox("Ascending", &sortAscending);
|
||||
|
||||
ImGui::Separator();
|
||||
ImGui::Text("Type Filters:");
|
||||
ImGui::Checkbox("Images", &showImages);
|
||||
ImGui::Checkbox("Audio", &showAudio);
|
||||
|
||||
ImGui::EndPopup();
|
||||
}
|
||||
|
||||
ImGui::PopStyleVar(2);
|
||||
|
||||
// Search field (spaced below buttons)
|
||||
ImGui::Spacing();
|
||||
ImGui::Spacing();
|
||||
|
||||
char buffer[256] = {};
|
||||
strncpy(buffer, assetSearchQuery.c_str(), sizeof(buffer) - 1);
|
||||
|
||||
if (ImGui::InputTextWithHint("##Search", "Search...", buffer, sizeof(buffer)))
|
||||
ImGui::SetNextItemWidth(-1);
|
||||
if (ImGui::InputTextWithHint("##Search", "Search", buffer, sizeof(buffer)))
|
||||
{
|
||||
assetSearchQuery = buffer;
|
||||
}
|
||||
|
||||
|
||||
|
||||
ImGui::Separator();
|
||||
ImGui::BeginChild("##AssetScroll", ImVec2(0, 0), true);
|
||||
|
||||
@ -56,25 +123,44 @@ void ShowAssetBrowser()
|
||||
|
||||
ImGui::Columns(columns, nullptr, false);
|
||||
|
||||
int idx = 0;
|
||||
for (const auto &[uaid, baseAsset] : AssetManager::GetAllAssets())
|
||||
// Collect, filter and sort assets
|
||||
std::vector<const AssetInfo *> sortedAssets;
|
||||
for (const auto &[uaid, asset] : AssetManager::GetAllAssets())
|
||||
{
|
||||
if (!baseAsset || !baseAsset->loaded)
|
||||
if (!asset || !asset->loaded)
|
||||
continue;
|
||||
|
||||
if (!assetSearchQuery.empty() &&
|
||||
baseAsset->filename.find(assetSearchQuery) == std::string::npos &&
|
||||
baseAsset->path.find(assetSearchQuery) == std::string::npos)
|
||||
{
|
||||
asset->filename.find(assetSearchQuery) == std::string::npos &&
|
||||
asset->path.find(assetSearchQuery) == std::string::npos)
|
||||
continue;
|
||||
|
||||
if ((asset->type == AssetType::Image && !showImages) ||
|
||||
(asset->type == AssetType::Audio && !showAudio))
|
||||
continue;
|
||||
|
||||
sortedAssets.push_back(asset.get());
|
||||
}
|
||||
|
||||
std::sort(sortedAssets.begin(), sortedAssets.end(), [](const AssetInfo *a, const AssetInfo *b)
|
||||
{
|
||||
switch (sortMode)
|
||||
{
|
||||
case 0: return sortAscending ? a->filename < b->filename : a->filename > b->filename;
|
||||
case 1: return sortAscending ? a->type < b->type : a->type > b->type;
|
||||
case 2: return sortAscending ? a->uaid < b->uaid : a->uaid > b->uaid;
|
||||
default: return true;
|
||||
} });
|
||||
|
||||
int idx = 0;
|
||||
for (const AssetInfo *baseAsset : sortedAssets)
|
||||
{
|
||||
ImGui::PushID(idx++);
|
||||
std::string displayName = GetFilenameFromPath(baseAsset->path);
|
||||
|
||||
if (baseAsset->type == AssetType::Image)
|
||||
{
|
||||
const auto *imageAsset = dynamic_cast<const ImageAssetInfo *>(baseAsset.get());
|
||||
const auto *imageAsset = dynamic_cast<const ImageAssetInfo *>(baseAsset);
|
||||
if (!imageAsset)
|
||||
{
|
||||
ImGui::PopID();
|
||||
@ -86,27 +172,23 @@ void ShowAssetBrowser()
|
||||
|
||||
if (ImGui::BeginDragDropSource(ImGuiDragDropFlags_SourceAllowNullID))
|
||||
{
|
||||
ImGui::SetDragDropPayload("ASSET_TEXTURE", &uaid, sizeof(uint64_t));
|
||||
ImGui::Image((ImTextureID)(intptr_t)imageAsset->textureID,
|
||||
ImVec2(thumbnailSize * 2, thumbnailSize * 2));
|
||||
ImGui::SetDragDropPayload("ASSET_TEXTURE", &baseAsset->uaid, sizeof(uint64_t));
|
||||
ImGui::Text("%s", displayName.c_str());
|
||||
ImGui::EndDragDropSource();
|
||||
}
|
||||
}
|
||||
else if (baseAsset->type == AssetType::Audio)
|
||||
{
|
||||
std::string buttonLabel = baseAsset->filetype.empty() ? "Audio" : (baseAsset->filetype);
|
||||
|
||||
std::string buttonLabel = baseAsset->filetype.empty() ? "Audio" : baseAsset->filetype;
|
||||
ImGui::Button(buttonLabel.c_str(), ImVec2(thumbnailSize, thumbnailSize));
|
||||
|
||||
if (ImGui::BeginDragDropSource(ImGuiDragDropFlags_SourceAllowNullID))
|
||||
{
|
||||
ImGui::SetDragDropPayload("ASSET_AUDIO", &uaid, sizeof(uint64_t));
|
||||
ImGui::Text("Audio: %s", displayName.c_str());
|
||||
ImGui::SetDragDropPayload("ASSET_AUDIO", &baseAsset->uaid, sizeof(uint64_t));
|
||||
ImGui::Text("%s", displayName.c_str());
|
||||
ImGui::EndDragDropSource();
|
||||
}
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
ImGui::PopID();
|
||||
@ -121,7 +203,7 @@ void ShowAssetBrowser()
|
||||
|
||||
if (baseAsset->type == AssetType::Image)
|
||||
{
|
||||
const auto *imageAsset = dynamic_cast<const ImageAssetInfo *>(baseAsset.get());
|
||||
const auto *imageAsset = dynamic_cast<const ImageAssetInfo *>(baseAsset);
|
||||
if (imageAsset)
|
||||
{
|
||||
ImGui::Text("Texture ID: %u", imageAsset->textureID);
|
||||
@ -141,7 +223,7 @@ void ShowAssetBrowser()
|
||||
if (ImGui::MenuItem("Unload"))
|
||||
{
|
||||
Logger::LogInfo("[AssetBrowser] Unloaded: %s", baseAsset->path.c_str());
|
||||
AssetManager::UnloadAsset(uaid);
|
||||
AssetManager::UnloadAsset(baseAsset->uaid);
|
||||
ImGui::EndPopup();
|
||||
ImGui::PopID();
|
||||
continue;
|
||||
|
@ -738,10 +738,12 @@ void DrawInspectorUI(std::shared_ptr<Object> selected)
|
||||
if (ImGui::Button("Stop"))
|
||||
audio->Stop();
|
||||
|
||||
// Looping
|
||||
static bool loop = false;
|
||||
loop = ImGui::Checkbox("Loop", &loop);
|
||||
if (ImGui::Checkbox("Loop", &loop))
|
||||
{
|
||||
audio->SetLooping(loop);
|
||||
}
|
||||
|
||||
|
||||
// Volume
|
||||
static float volume = 1.0f;
|
||||
|
@ -24,6 +24,8 @@ std::string GenerateUUID() {
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
|
||||
|
||||
UID::UID()
|
||||
: id(nextID++), uuid(GenerateUUID()) {}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user