diff --git a/imgui.ini b/imgui.ini index a3a7e4d..33240e3 100644 --- a/imgui.ini +++ b/imgui.ini @@ -10,97 +10,93 @@ Collapsed=1 [Window][WindowOverViewport_11111111] Pos=0,19 -Size=1280,701 +Size=1920,1158 Collapsed=0 [Window][Inspector] -Pos=0,421 -Size=342,299 +Pos=1578,19 +Size=342,1158 Collapsed=0 -DockId=0x0000000A,0 +DockId=0x00000006,0 [Window][Scene Tree] Pos=0,19 -Size=342,400 +Size=342,575 Collapsed=0 -DockId=0x00000009,0 +DockId=0x00000003,0 [Window][Viewport] Pos=344,19 -Size=936,139 +Size=1232,847 Collapsed=0 -DockId=0x0000000B,0 +DockId=0x00000007,0 [Window][##MainMenuBar] Size=1920,19 Collapsed=0 [Window][Performance Info] -Pos=1083,410 -Size=197,310 +Pos=0,19 +Size=342,575 Collapsed=0 -DockId=0x00000006,0 +DockId=0x00000003,1 [Window][Console] -Pos=344,410 -Size=286,310 +Pos=344,868 +Size=1232,309 Collapsed=0 -DockId=0x0000000D,0 +DockId=0x00000008,0 [Window][Tilemap Editor] Pos=265,19 Size=1263,674 Collapsed=0 -DockId=0x0000000B,1 +DockId=0x00000007,1 [Window][Profiler] -Pos=344,160 -Size=936,248 +Pos=344,868 +Size=1232,309 Collapsed=0 -DockId=0x0000000C,0 +DockId=0x00000008,1 [Window][Profiler Timeline] Pos=265,69 Size=623,651 Collapsed=0 -DockId=0x00000005,1 +DockId=0x00000008,1 [Window][Profiler (Unity Style)] Pos=265,430 Size=623,290 Collapsed=0 -DockId=0x00000005,1 +DockId=0x00000008,1 [Window][Profiler Timeline View] Pos=265,526 Size=1263,651 Collapsed=0 -DockId=0x00000005,1 +DockId=0x00000008,1 [Window][Color Correction] -Pos=1083,410 -Size=197,310 +Pos=1588,867 +Size=332,310 Collapsed=0 -DockId=0x00000006,1 +DockId=0x00000008,1 [Window][Asset Browser] -Pos=632,410 -Size=449,310 +Pos=0,596 +Size=342,581 Collapsed=0 -DockId=0x0000000E,0 +DockId=0x00000004,0 [Docking][Data] -DockSpace ID=0x11111111 Window=0x1BBC0F80 Pos=0,19 Size=1280,701 Split=X - DockNode ID=0x00000001 Parent=0x11111111 SizeRef=342,701 Split=Y Selected=0x12EF0F59 - DockNode ID=0x00000009 Parent=0x00000001 SizeRef=385,662 Selected=0x12EF0F59 - DockNode ID=0x0000000A Parent=0x00000001 SizeRef=385,494 HiddenTabBar=1 Selected=0x36DC96AB - DockNode ID=0x00000002 Parent=0x11111111 SizeRef=1576,701 Split=Y Selected=0xC450F867 - DockNode ID=0x00000007 Parent=0x00000002 SizeRef=606,846 Split=Y Selected=0xC450F867 - DockNode ID=0x0000000B Parent=0x00000007 SizeRef=1576,596 CentralNode=1 HiddenTabBar=1 Selected=0xC450F867 - DockNode ID=0x0000000C Parent=0x00000007 SizeRef=1576,248 HiddenTabBar=1 Selected=0x9B5D3198 - DockNode ID=0x00000008 Parent=0x00000002 SizeRef=606,310 Split=X Selected=0x9B5D3198 - DockNode ID=0x00000005 Parent=0x00000008 SizeRef=1242,481 Split=X Selected=0x9B5D3198 - DockNode ID=0x0000000D Parent=0x00000005 SizeRef=482,248 HiddenTabBar=1 Selected=0xEA83D666 - DockNode ID=0x0000000E Parent=0x00000005 SizeRef=758,248 HiddenTabBar=1 Selected=0x36AF052B - DockNode ID=0x00000006 Parent=0x00000008 SizeRef=332,481 Selected=0xA873C17F +DockSpace ID=0x11111111 Window=0x1BBC0F80 Pos=0,19 Size=1920,1158 Split=X + DockNode ID=0x00000005 Parent=0x11111111 SizeRef=1576,1158 Split=X + DockNode ID=0x00000001 Parent=0x00000005 SizeRef=342,701 Split=Y Selected=0x12EF0F59 + DockNode ID=0x00000003 Parent=0x00000001 SizeRef=342,575 Selected=0x12EF0F59 + DockNode ID=0x00000004 Parent=0x00000001 SizeRef=342,581 HiddenTabBar=1 Selected=0x36AF052B + DockNode ID=0x00000002 Parent=0x00000005 SizeRef=1576,701 Split=Y Selected=0xC450F867 + DockNode ID=0x00000007 Parent=0x00000002 SizeRef=606,847 CentralNode=1 HiddenTabBar=1 Selected=0xC450F867 + DockNode ID=0x00000008 Parent=0x00000002 SizeRef=606,309 Selected=0x9B5D3198 + DockNode ID=0x00000006 Parent=0x11111111 SizeRef=342,1158 Selected=0x36DC96AB diff --git a/remake/build.log b/remake/build.log index f82fd2b..261f46c 100644 --- a/remake/build.log +++ b/remake/build.log @@ -1,15 +1,5 @@ -[COMPILE] g++ -std=c++20 -Wall -g -Isrc/include -Isrc/include/lua -Isrc/vendor -Isrc/vendor/imgui -Isrc/vendor/box2d -IC:/msys64/mingw64/include -IC:\msys64\mingw64\lib\libyaml-cpp.a -Isrc\vendor\imgui -MMD -MP -c src\src\core\utils\Texture.cpp -o src\build\core\utils\Texture.o -[COMPILE] g++ -std=c++20 -Wall -g -Isrc/include -Isrc/include/lua -Isrc/vendor -Isrc/vendor/imgui -Isrc/vendor/box2d -IC:/msys64/mingw64/include -IC:\msys64\mingw64\lib\libyaml-cpp.a -Isrc\vendor\imgui -MMD -MP -c src\src\editor\windows\AssetBrowser.cpp -o src\build\editor\windows\AssetBrowser.o -[COMPILE] g++ -std=c++20 -Wall -g -Isrc/include -Isrc/include/lua -Isrc/vendor -Isrc/vendor/imgui -Isrc/vendor/box2d -IC:/msys64/mingw64/include -IC:\msys64\mingw64\lib\libyaml-cpp.a -Isrc\vendor\imgui -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 -IC:/msys64/mingw64/include -IC:\msys64\mingw64\lib\libyaml-cpp.a -Isrc\vendor\imgui -MMD -MP -c src\src\Components\ScriptComponent.cpp -o src\build\Components\ScriptComponent.o -[COMPILE] g++ -std=c++20 -Wall -g -Isrc/include -Isrc/include/lua -Isrc/vendor -Isrc/vendor/imgui -Isrc/vendor/box2d -IC:/msys64/mingw64/include -IC:\msys64\mingw64\lib\libyaml-cpp.a -Isrc\vendor\imgui -MMD -MP -c src\src\Components\TilemapComponent.cpp -o src\build\Components\TilemapComponent.o -[COMPILE] g++ -std=c++20 -Wall -g -Isrc/include -Isrc/include/lua -Isrc/vendor -Isrc/vendor/imgui -Isrc/vendor/box2d -IC:/msys64/mingw64/include -IC:\msys64\mingw64\lib\libyaml-cpp.a -Isrc\vendor\imgui -MMD -MP -c src\src\core\utils\Profiler.cpp -o src\build\core\utils\Profiler.o -[COMPILE] g++ -std=c++20 -Wall -g -Isrc/include -Isrc/include/lua -Isrc/vendor -Isrc/vendor/imgui -Isrc/vendor/box2d -IC:/msys64/mingw64/include -IC:\msys64\mingw64\lib\libyaml-cpp.a -Isrc\vendor\imgui -MMD -MP -c src\src\Renderer.cpp -o src\build\Renderer.o -[COMPILE] g++ -std=c++20 -Wall -g -Isrc/include -Isrc/include/lua -Isrc/vendor -Isrc/vendor/imgui -Isrc/vendor/box2d -IC:/msys64/mingw64/include -IC:\msys64\mingw64\lib\libyaml-cpp.a -Isrc\vendor\imgui -MMD -MP -c src\src\Components\ParticleComponent.cpp -o src\build\Components\ParticleComponent.o +[COMPILE] g++ -std=c++20 -Wall -g -Isrc/include -Isrc/include/lua -Isrc/vendor -Isrc/vendor/imgui -Isrc/vendor/box2d -IC:/msys64/mingw64/include -IC:\msys64\mingw64\lib\libyaml-cpp.a -Isrc\vendor\imgui -MMD -MP -c src\src\Components\AnimationComponent.cpp -o src\build\Components\AnimationComponent.o [COMPILE] g++ -std=c++20 -Wall -g -Isrc/include -Isrc/include/lua -Isrc/vendor -Isrc/vendor/imgui -Isrc/vendor/box2d -IC:/msys64/mingw64/include -IC:\msys64\mingw64\lib\libyaml-cpp.a -Isrc\vendor\imgui -MMD -MP -c src\src\editor\windows\Inspector.cpp -o src\build\editor\windows\Inspector.o -[COMPILE] g++ -std=c++20 -Wall -g -Isrc/include -Isrc/include/lua -Isrc/vendor -Isrc/vendor/imgui -Isrc/vendor/box2d -IC:/msys64/mingw64/include -IC:\msys64\mingw64\lib\libyaml-cpp.a -Isrc\vendor\imgui -MMD -MP -c src\src\core\utils\EngineConfig.cpp -o src\build\core\utils\EngineConfig.o -[COMPILE] g++ -std=c++20 -Wall -g -Isrc/include -Isrc/include/lua -Isrc/vendor -Isrc/vendor/imgui -Isrc/vendor/box2d -IC:/msys64/mingw64/include -IC:\msys64\mingw64\lib\libyaml-cpp.a -Isrc\vendor\imgui -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 -IC:/msys64/mingw64/include -IC:\msys64\mingw64\lib\libyaml-cpp.a -Isrc\vendor\imgui -MMD -MP -c src\src\Components\SpriteComponent.cpp -o src\build\Components\SpriteComponent.o -[COMPILE] g++ -std=c++20 -Wall -g -Isrc/include -Isrc/include/lua -Isrc/vendor -Isrc/vendor/imgui -Isrc/vendor/box2d -IC:/msys64/mingw64/include -IC:\msys64\mingw64\lib\libyaml-cpp.a -Isrc\vendor\imgui -MMD -MP -c src\src\Engine.cpp -o src\build\Engine.o -[LINK] g++ src\build\Engine.o src\build\main.o src\build\Renderer.o src\build\Components\AnimationComponent.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\utils\AssetLoader.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\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\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 -o src\build\app.exe -LC:\msys64\mingw64\lib -lglfw3 -lglew32 -lopengl32 -lgdi32 -lyaml-cpp -lcomdlg32 -lssl -lcrypto -[RUN] Executed app.exe successfully. +[LINK] g++ src\build\Engine.o src\build\main.o src\build\Renderer.o src\build\Components\AnimationComponent.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\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\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\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 -o src\build\app.exe -LC:\msys64\mingw64\lib -lglfw3 -lglew32 -lopengl32 -lgdi32 -lyaml-cpp -lcomdlg32 -lssl -lcrypto +[ERROR] Runtime crash +Command 'src\build\app.exe' returned non-zero exit status 3221225477. diff --git a/src/assets/scenes/animation.cene b/src/assets/scenes/animation.cene new file mode 100644 index 0000000..60cf1ef --- /dev/null +++ b/src/assets/scenes/animation.cene @@ -0,0 +1,26 @@ +engine_version: 0.1.0 +scene_name: Animation Test +scene_hash: 4118ae64656b78eaaae99b4b2b842496e6c90b20ec8399a165be0bdfa3e80bdc +format_version: 1 +objects: + - name: Hello, Create + uid: 19b6b2eb03084eae822f776ba886f55b + id: 0 + position: [0, 0] + rotation: 0 + layer: 0 + visable: true + components: + - AnimationComponent + - TexturePath: C:\Users\spenc\OneDrive\Pictures\Pixel Holy Spell Effect 32x32 Pack 3\01.png + TexelWidth: 64 + TexelHeight: 64 + FrameDuration: 0.100000000 + children: [] +color_correction: + brightness: 1 + saturation: 1 + gamma: 1 + bloom: false + intensity: 1.20000005 + threshold: 0.200000003 \ No newline at end of file diff --git a/src/assets/scenes/assettest.cene b/src/assets/scenes/assettest.cene new file mode 100644 index 0000000..e01b4ca --- /dev/null +++ b/src/assets/scenes/assettest.cene @@ -0,0 +1,35 @@ +engine_version: 0.1.0 +scene_name: New Text Document +scene_hash: d3b8c771af41a9f6021a650b384379cd3582e59a8e167c0e06e99643d29ad97b +format_version: 1 +objects: + - name: Hello, Create + uid: fced127a6c9c485cb3dd1b947e1429f9 + id: 0 + position: [0, 0] + rotation: 0 + layer: 0 + visable: true + components: + - AnimationComponent + - TexturePath: C:\Users\spenc\OneDrive\Pictures\6656e7221e49a1774d2fb280357e56f8d25d9d95.png + TexelWidth: 32 + TexelHeight: 32 + FrameDuration: 0.100000001 + StartFrame: 0 + EndFrame: 1023 + children: [] +color_correction: + brightness: 1 + saturation: 1 + gamma: 1 + bloom: true + intensity: 1.20000005 + threshold: 1 +assets: Assets +? - uaid: 1 + path: C:\Users\spenc\OneDrive\Pictures\6656e7221e49a1774d2fb280357e56f8d25d9d95.png + filename: 6656e7221e49a1774d2fb280357e56f8d25d9d95.png + filetype: png + type: 0 + size: [1024, 1024] \ No newline at end of file diff --git a/src/assets/scenes/lighting_test.cene b/src/assets/scenes/lighting_test.cene index 261877a..036971c 100644 --- a/src/assets/scenes/lighting_test.cene +++ b/src/assets/scenes/lighting_test.cene @@ -1,6 +1,6 @@ engine_version: 0.1.0 scene_name: lighting_test -scene_hash: 964a6472a140773c791bf1ed2b8e6ea5b20b183e7bb02489110ad41df5d364e2 +scene_hash: ee7d7a88a6c1a4eaa0ae27372e3d055df3511e13144a267574ebb7a7842d63d2 format_version: 1 objects: - name: Tiles @@ -21,86 +21,47 @@ objects: visable: true components: - type: SpriteComponent - texture: C:\Users\spenc\OneDrive\Pictures\textures\bark_willow_02_diff_1k.png - normalMap: C:\Users\spenc\OneDrive\Pictures\textures\bark_willow_02_nor_gl_1k.png + texture: 1 + normalMap: 2 renderType: Lit children: [] - name: Planks uid: 13d8988343354e3c8a1f51c03ed40cda id: 5 - position: [1024, 0] + position: [2048, 0] rotation: 0 layer: 0 visable: true components: - type: SpriteComponent - texture: C:\Users\spenc\OneDrive\Pictures\textures\wood_floor_worn_diff_1k.png - normalMap: C:\Users\spenc\OneDrive\Pictures\textures\wood_floor_worn_nor_gl_1k.png + texture: 3 + normalMap: 4 renderType: Lit children: [] - name: Rocks uid: cff28abe7e3b455ab9b756acc84cd2d7 id: 6 - position: [0, 1024] + position: [0, 2048] rotation: 0 layer: 0 visable: true components: - type: SpriteComponent - texture: C:\Users\spenc\OneDrive\Pictures\textures\ganges_river_pebbles_diff_1k.png - normalMap: C:\Users\spenc\OneDrive\Pictures\textures\ganges_river_pebbles_nor_gl_1k.png + texture: 6 + normalMap: 5 renderType: Lit children: [] - name: Metal uid: 98967eb30e5b429b992766d8062b7c17 id: 7 - position: [1024, 1024] + position: [2048, 2048] rotation: 0 layer: 0 visable: true components: - type: SpriteComponent - texture: C:\Users\spenc\OneDrive\Pictures\textures\metal_plate_diff_1k.png - normalMap: C:\Users\spenc\OneDrive\Pictures\textures\metal_plate_nor_gl_1k.png - renderType: Lit - children: [] - - name: Logo - uid: c4ce6f16dfb347b0ae0ac67f5881b243 - id: 8 - position: [3181, 56] - rotation: 0 - layer: 0 - visable: true - components: - - type: SpriteComponent - texture: C:\Users\spenc\OneDrive\Pictures\blue_logo.png - normalMap: C:\Users\spenc\OneDrive\Pictures\textures\circuits_normal.jpg - renderType: Lit - children: [] - - name: Carbooon Fobar - uid: 5ea269572751401da6d86519d3513b7d - id: 9 - position: [4087.8999, 3070] - rotation: 0 - layer: 1 - visable: true - components: - - type: SpriteComponent - texture: C:\Users\spenc\OneDrive\Pictures\textures\carbon-fiber-smooth-bl\carbon-fiber-smooth-bl\carbon-fiber_smooth_albedo.png - normalMap: C:\Users\spenc\OneDrive\Pictures\textures\carbon-fiber-smooth-bl\carbon-fiber-smooth-bl\carbon-fiber_smooth_normal-ogl.png - renderType: Lit - children: [] - - name: Carbooon Fobar 2 - uid: a36b71937ba349bd8e6414f75be9ee16 - id: 10 - position: [-7.69999981, 3070] - rotation: 0 - layer: 0 - visable: true - components: - - type: SpriteComponent - texture: C:\Users\spenc\OneDrive\Pictures\textures\carbon-fiber-smooth-bl\carbon-fiber-smooth-bl\carbon-fiber_smooth_albedo.png - normalMap: C:\Users\spenc\OneDrive\Pictures\textures\carbon-fiber-smooth-bl\carbon-fiber-smooth-bl\carbon-fiber_smooth_normal-ogl.png + texture: 7 + normalMap: 8 renderType: Lit children: [] - name: Lights @@ -115,7 +76,7 @@ objects: - name: Red uid: 6afde2dd47aa4557b6afb1a607c99dc8 id: 13 - position: [878.398376, 545.669373] + position: [574.239258, 805.561768] rotation: 0 layer: 2 visable: true @@ -133,7 +94,7 @@ objects: - name: Green uid: 0f950d76d24b4dc18f54cab2c3aaaf9a id: 14 - position: [1511.04724, 1137.07068] + position: [1438.05347, 743.714905] rotation: 0 layer: 2 visable: true @@ -151,7 +112,7 @@ objects: - name: Blue uid: 09f722f51c7c4b0f98de3a0a16d127c4 id: 15 - position: [682.554321, 1389.26001] + position: [1059.70728, 1522.72339] rotation: 0 layer: 2 visable: true @@ -232,6 +193,7 @@ objects: endColor: [0.792156875, 0, 1, 1] loop: true burst: false + roundness: 1 children: [] - name: Rain uid: 19253834f75d4e69a618c45ddb14e8b0 @@ -256,6 +218,7 @@ objects: endColor: [0, 0, 1, 0] loop: true burst: false + roundness: 1 children: [] - name: Fire uid: 995af3d194694309a490504eaee3ae92 @@ -280,11 +243,61 @@ objects: endColor: [1, 0, 0, 0] loop: true burst: false + roundness: 1 children: [] color_correction: brightness: 2 saturation: 2 gamma: 1.05999994 bloom: true - intensity: 1.40999997 - threshold: 0.300000012 \ No newline at end of file + intensity: 1.35000002 + threshold: 0.810000002 +Assets: + - uaid: 1 + path: C:\Users\spenc\OneDrive\Pictures\textures\bark_willow_02_diff_1k.png + filename: bark_willow_02_diff_1k.png + filetype: png + type: 0 + size: [1024, 1024] + - uaid: 2 + path: C:\Users\spenc\OneDrive\Pictures\textures\bark_willow_02_nor_gl_1k.png + filename: bark_willow_02_nor_gl_1k.png + filetype: png + type: 0 + size: [1024, 1024] + - uaid: 3 + path: C:\Users\spenc\OneDrive\Pictures\textures\wood_floor_worn_diff_1k.png + filename: wood_floor_worn_diff_1k.png + filetype: png + type: 0 + size: [1024, 1024] + - uaid: 4 + path: C:\Users\spenc\OneDrive\Pictures\textures\wood_floor_worn_nor_gl_1k.png + filename: wood_floor_worn_nor_gl_1k.png + filetype: png + type: 0 + size: [1024, 1024] + - uaid: 5 + path: C:\Users\spenc\OneDrive\Pictures\textures\ganges_river_pebbles_nor_gl_1k.png + filename: ganges_river_pebbles_nor_gl_1k.png + filetype: png + type: 0 + size: [1024, 1024] + - uaid: 6 + path: C:\Users\spenc\OneDrive\Pictures\textures\ganges_river_pebbles_diff_1k.png + filename: ganges_river_pebbles_diff_1k.png + filetype: png + type: 0 + size: [1024, 1024] + - uaid: 7 + path: C:\Users\spenc\OneDrive\Pictures\textures\metal_plate_diff_1k.png + filename: metal_plate_diff_1k.png + filetype: png + type: 0 + size: [1024, 1024] + - uaid: 8 + path: C:\Users\spenc\OneDrive\Pictures\textures\metal_plate_nor_gl_1k.png + filename: metal_plate_nor_gl_1k.png + filetype: png + type: 0 + size: [1024, 1024] \ No newline at end of file diff --git a/src/assets/scenes/lighting_test_2.cene b/src/assets/scenes/lighting_test_2.cene index be82ddd..1bb5069 100644 --- a/src/assets/scenes/lighting_test_2.cene +++ b/src/assets/scenes/lighting_test_2.cene @@ -1,12 +1,12 @@ engine_version: 0.1.0 scene_name: lighting_test_2 -scene_hash: 8d1aa1b7b386c5e68c5ad14aa2db10dad6c1fef078b7cbd009df408784b8f915 +scene_hash: fd4d1e65a004b05f9654d657efa90617ff63d3c6c4e624518825d4dae50ef3a3 format_version: 1 objects: - name: Tiles uid: f5e01f7892874a67b662633650b41dbd id: 3 - position: [0, 0] + position: [426, 1088] rotation: 0 layer: 0 visable: true @@ -21,86 +21,47 @@ objects: visable: true components: - type: SpriteComponent - texture: C:\Users\spenc\OneDrive\Pictures\textures\bark_willow_02_diff_1k.png - normalMap: C:\Users\spenc\OneDrive\Pictures\textures\bark_willow_02_nor_gl_1k.png + texture: 1 + normalMap: 2 renderType: Lit children: [] - name: Planks uid: 13d8988343354e3c8a1f51c03ed40cda id: 5 - position: [1024, 0] + position: [2048, 0] rotation: 0 layer: 0 visable: true components: - type: SpriteComponent - texture: C:\Users\spenc\OneDrive\Pictures\textures\wood_floor_worn_diff_1k.png - normalMap: C:\Users\spenc\OneDrive\Pictures\textures\wood_floor_worn_nor_gl_1k.png + texture: 3 + normalMap: 4 renderType: Lit children: [] - name: Rocks uid: cff28abe7e3b455ab9b756acc84cd2d7 id: 6 - position: [0, 1024] + position: [0, 2048] rotation: 0 layer: 0 visable: true components: - type: SpriteComponent - texture: C:\Users\spenc\OneDrive\Pictures\textures\ganges_river_pebbles_diff_1k.png - normalMap: C:\Users\spenc\OneDrive\Pictures\textures\ganges_river_pebbles_nor_gl_1k.png + texture: 6 + normalMap: 5 renderType: Lit children: [] - name: Metal uid: 98967eb30e5b429b992766d8062b7c17 id: 7 - position: [1024, 1024] + position: [2048, 2048] rotation: 0 layer: 0 visable: true components: - type: SpriteComponent - texture: C:\Users\spenc\OneDrive\Pictures\textures\metal_plate_diff_1k.png - normalMap: C:\Users\spenc\OneDrive\Pictures\textures\metal_plate_nor_gl_1k.png - renderType: Lit - children: [] - - name: Logo - uid: c4ce6f16dfb347b0ae0ac67f5881b243 - id: 8 - position: [3181, 56] - rotation: 0 - layer: 0 - visable: true - components: - - type: SpriteComponent - texture: C:\Users\spenc\OneDrive\Pictures\blue_logo.png - normalMap: C:\Users\spenc\OneDrive\Pictures\textures\circuits_normal.jpg - renderType: Lit - children: [] - - name: Carbooon Fobar - uid: 5ea269572751401da6d86519d3513b7d - id: 9 - position: [4087.8999, 3070] - rotation: 0 - layer: 1 - visable: true - components: - - type: SpriteComponent - texture: C:\Users\spenc\OneDrive\Pictures\textures\carbon-fiber-smooth-bl\carbon-fiber-smooth-bl\carbon-fiber_smooth_albedo.png - normalMap: C:\Users\spenc\OneDrive\Pictures\textures\carbon-fiber-smooth-bl\carbon-fiber-smooth-bl\carbon-fiber_smooth_normal-ogl.png - renderType: Lit - children: [] - - name: Carbooon Fobar 2 - uid: a36b71937ba349bd8e6414f75be9ee16 - id: 10 - position: [-7.69999981, 3070] - rotation: 0 - layer: 0 - visable: true - components: - - type: SpriteComponent - texture: C:\Users\spenc\OneDrive\Pictures\textures\carbon-fiber-smooth-bl\carbon-fiber-smooth-bl\carbon-fiber_smooth_albedo.png - normalMap: C:\Users\spenc\OneDrive\Pictures\textures\carbon-fiber-smooth-bl\carbon-fiber-smooth-bl\carbon-fiber_smooth_normal-ogl.png + texture: 7 + normalMap: 8 renderType: Lit children: [] - name: Lights @@ -115,7 +76,7 @@ objects: - name: Red uid: 6afde2dd47aa4557b6afb1a607c99dc8 id: 13 - position: [574.239258, 805.561768] + position: [1062.8678, 525.513] rotation: 0 layer: 2 visable: true @@ -133,7 +94,7 @@ objects: - name: Green uid: 0f950d76d24b4dc18f54cab2c3aaaf9a id: 14 - position: [1438.05347, 743.714905] + position: [1436.26843, 1306.90405] rotation: 0 layer: 2 visable: true @@ -151,7 +112,7 @@ objects: - name: Blue uid: 09f722f51c7c4b0f98de3a0a16d127c4 id: 15 - position: [1059.70728, 1522.72339] + position: [572.863647, 1239.58301] rotation: 0 layer: 2 visable: true @@ -232,6 +193,7 @@ objects: endColor: [0.792156875, 0, 1, 1] loop: true burst: false + roundness: 1 children: [] - name: Rain uid: 19253834f75d4e69a618c45ddb14e8b0 @@ -256,6 +218,7 @@ objects: endColor: [0, 0, 1, 0] loop: true burst: false + roundness: 1 children: [] - name: Fire uid: 995af3d194694309a490504eaee3ae92 @@ -280,11 +243,61 @@ objects: endColor: [1, 0, 0, 0] loop: true burst: false + roundness: 1 children: [] color_correction: brightness: 2 saturation: 2 gamma: 1.05999994 bloom: true - intensity: 1.40999997 - threshold: 0.300000012 \ No newline at end of file + intensity: 0.200000003 + threshold: 1.75999999 +Assets: + - uaid: 1 + path: C:\Users\spenc\OneDrive\Pictures\textures\bark_willow_02_diff_1k.png + filename: bark_willow_02_diff_1k.png + filetype: png + type: 0 + size: [1024, 1024] + - uaid: 2 + path: C:\Users\spenc\OneDrive\Pictures\textures\bark_willow_02_nor_gl_1k.png + filename: bark_willow_02_nor_gl_1k.png + filetype: png + type: 0 + size: [1024, 1024] + - uaid: 3 + path: C:\Users\spenc\OneDrive\Pictures\textures\wood_floor_worn_diff_1k.png + filename: wood_floor_worn_diff_1k.png + filetype: png + type: 0 + size: [1024, 1024] + - uaid: 4 + path: C:\Users\spenc\OneDrive\Pictures\textures\wood_floor_worn_nor_gl_1k.png + filename: wood_floor_worn_nor_gl_1k.png + filetype: png + type: 0 + size: [1024, 1024] + - uaid: 5 + path: C:\Users\spenc\OneDrive\Pictures\textures\ganges_river_pebbles_nor_gl_1k.png + filename: ganges_river_pebbles_nor_gl_1k.png + filetype: png + type: 0 + size: [1024, 1024] + - uaid: 6 + path: C:\Users\spenc\OneDrive\Pictures\textures\ganges_river_pebbles_diff_1k.png + filename: ganges_river_pebbles_diff_1k.png + filetype: png + type: 0 + size: [1024, 1024] + - uaid: 7 + path: C:\Users\spenc\OneDrive\Pictures\textures\metal_plate_diff_1k.png + filename: metal_plate_diff_1k.png + filetype: png + type: 0 + size: [1024, 1024] + - uaid: 8 + path: C:\Users\spenc\OneDrive\Pictures\textures\metal_plate_nor_gl_1k.png + filename: metal_plate_nor_gl_1k.png + filetype: png + type: 0 + size: [1024, 1024] \ No newline at end of file diff --git a/src/assets/shaders/sprite.frag b/src/assets/shaders/sprite.frag index 457cc98..b09523c 100644 --- a/src/assets/shaders/sprite.frag +++ b/src/assets/shaders/sprite.frag @@ -1,6 +1,10 @@ #version 430 core in vec2 vUV; + +uniform vec2 uUVMin; +uniform vec2 uUVMax; + in vec2 vFragScreenPos; out vec4 FragColor; @@ -18,6 +22,8 @@ uniform int uClusterHeight; uniform int uClusterCols; uniform int uMaxLightsPerCluster; + + #define MAX_LIGHTS 512 uniform vec2 uLightPos[MAX_LIGHTS]; uniform vec3 uLightColor[MAX_LIGHTS]; @@ -30,7 +36,9 @@ layout(std430, binding = 1) readonly buffer ClusterLightBuffer { void main() { - vec2 rotatedUV = vec2(vUV.y, 1.0 - vUV.x); + + vec2 rotatedUV = mix(uUVMin, uUVMax, vec2(vUV.y, 1.0 - vUV.x)); + vec4 texColor = texture(uTex, rotatedUV); if (texColor.a < 0.1) discard; diff --git a/src/assets/shaders/unlit.frag b/src/assets/shaders/unlit.frag index 321d3e2..3b48e8a 100644 --- a/src/assets/shaders/unlit.frag +++ b/src/assets/shaders/unlit.frag @@ -1,15 +1,21 @@ #version 330 core + in vec2 vUV; out vec4 FragColor; uniform sampler2D uTex; +uniform vec2 uUVMin; +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); - vec4 color = texture(uTex, rotatedUV); + // Interpolate UVs within atlas range + vec2 uv = mix(uUVMin, uUVMax, rotatedUV); + + vec4 color = texture(uTex, uv); if (color.a < 0.01) discard; diff --git a/src/assets/shaders/unlit.vert b/src/assets/shaders/unlit.vert index e9ed802..039a990 100644 --- a/src/assets/shaders/unlit.vert +++ b/src/assets/shaders/unlit.vert @@ -1,4 +1,4 @@ -#version 330 core +#version 430 core layout (location = 0) in vec2 aPos; layout (location = 1) in vec2 aUV; diff --git a/src/assets/shaders/unlit_quad.frag b/src/assets/shaders/unlit_quad.frag index 316ad03..05f3145 100644 --- a/src/assets/shaders/unlit_quad.frag +++ b/src/assets/shaders/unlit_quad.frag @@ -1,11 +1,23 @@ #version 330 core in vec4 vColor; +in vec2 vUV; +in float vRoundness; + out vec4 FragColor; -void main() { - // Optional: kill particles with near-zero alpha (optional) - if (vColor.a < 0.01) +void main() +{ + vec2 pos = vUV * 2.0 - 1.0; + vec2 absPos = abs(pos); + + bool insideSquare = all(lessThanEqual(absPos, vec2(1.0))); + + bool insideCircle = length(pos) <= 1.0; + + bool inside = mix(float(insideSquare), float(insideCircle), vRoundness) >= 0.5; + + if (!inside) discard; FragColor = vColor; diff --git a/src/assets/shaders/unlit_quad.vert b/src/assets/shaders/unlit_quad.vert index c00b2e4..afe6dac 100644 --- a/src/assets/shaders/unlit_quad.vert +++ b/src/assets/shaders/unlit_quad.vert @@ -1,4 +1,4 @@ -#version 330 core +#version 430 core layout (location = 0) in vec2 aPos; @@ -6,12 +6,17 @@ layout (location = 1) in vec2 iPos; layout (location = 2) in vec2 iSize; layout (location = 3) in float iRot; layout (location = 4) in vec4 iColor; +layout (location = 5) in float iRoundness; // 0 to 1 rounded uniform vec2 uScreen; out vec4 vColor; +out float vRoundness; +out vec2 vUV; -void main() { + +void main() +{ float cosR = cos(iRot); float sinR = sin(iRot); @@ -24,5 +29,9 @@ void main() { vec2 finalPos = iPos + rotated; gl_Position = vec4((finalPos / uScreen * 2.0 - 1.0) * vec2(1, -1), 0.0, 1.0); + + // Map [-0.5, 0.5] to [0.0, 1.0] + vUV = aPos + vec2(0.5); vColor = iColor; + vRoundness = iRoundness; } diff --git a/src/src/Components/AnimationComponent.cpp b/src/src/Components/AnimationComponent.cpp index 1db0edc..c8e3148 100644 --- a/src/src/Components/AnimationComponent.cpp +++ b/src/src/Components/AnimationComponent.cpp @@ -1,71 +1,117 @@ #include "AnimationComponent.h" -AnimationComponent::AnimationComponent(Object* owner) +AnimationComponent::AnimationComponent(Object *owner) : Component(owner) {} - void AnimationComponent::SetTextureAtlas(const std::string& path, int cols, int rows, float duration) { - texturePath = path; - texture = std::make_shared(path); - atlas = TextureAtlas(texture, cols, rows); - columns = cols; - rows = rows; - totalFrames = cols * rows; - frameDuration = duration; +void AnimationComponent::SetTextureAtlasPath(const std::string &path, int texelWidth, int texelHeight, float duration, int start, int end) +{ + AssetManager::LoadAssetAsync(path, AssetType::Image); + const auto *asset = AssetManager::GetAssetByPath(path); + if (asset) + SetTextureAtlas(asset->uaid, texelWidth, texelHeight, duration, start, end); +} + +void AnimationComponent::SetTextureAtlas(uint64_t uaid, int texelWidth, int texelHeight, float duration, int /*start*/, int /*end*/) +{ + textureUAID = uaid; + + const auto *asset = AssetManager::GetAssetByID(uaid); + if (!asset || !asset->loaded) + { + Logger::LogError("SetTextureAtlas: Asset not found or not loaded (UAID: %llu)", uaid); + return; } - + + int texWidth = static_cast(asset->size.x); + int texHeight = static_cast(asset->size.y); + + if (texelWidth <= 0 || texelHeight <= 0 || texWidth < texelWidth || texHeight < texelHeight) + { + Logger::LogError("SetTextureAtlas: Invalid texel size %dx%d for image size %dx%d (UAID: %llu)", + texelWidth, texelHeight, texWidth, texHeight, uaid); + return; + } + + if (texWidth % texelWidth != 0 || texHeight % texelHeight != 0) + { + Logger::LogWarning("SetTextureAtlas: Texture size is not cleanly divisible by texel size (UAID: %llu)", uaid); + } + + texture = std::make_shared(asset->uaid); + + atlas.texture = texture; + atlas.SetTexelSize(texelWidth, texelHeight); + + columns = texWidth / texelWidth; + rows = texHeight / texelHeight; + totalFrames = columns * rows; + + startFrame = 0; + endFrame = totalFrames > 0 ? totalFrames - 1 : 0; + + frameDuration = duration; + currentFrame = startFrame; + + renderType = RenderType::Unlit; +} void AnimationComponent::Play() { playing = true; } void AnimationComponent::Stop() { playing = false; } void AnimationComponent::SetLooping(bool l) { loop = l; } void AnimationComponent::SetSpeed(float s) { speed = s; } -void AnimationComponent::SetFrame(int f) { currentFrame = f % totalFrames; } +void AnimationComponent::SetFrame(int f) { currentFrame = std::clamp(f, startFrame, endFrame); } -void AnimationComponent::Update(float dt) { - if (!playing || totalFrames <= 1) return; +void AnimationComponent::Update(float dt) +{ + if (!playing || totalFrames <= 1) + return; time += dt * speed; - if (time >= frameDuration) { + if (time >= frameDuration) + { time -= frameDuration; currentFrame++; - if (currentFrame >= totalFrames) { + if (currentFrame > endFrame) + { if (loop) - currentFrame = 0; - else { - currentFrame = totalFrames - 1; + currentFrame = startFrame; + else + { + currentFrame = endFrame; playing = false; } } } } +std::string AnimationComponent::GetName() const { return "AnimationComponent"; } - -std::string AnimationComponent::GetName() const { - return "AnimationComponent"; -} - -void AnimationComponent::Save(YAML::Emitter& out) const { +void AnimationComponent::Save(YAML::Emitter &out) const +{ out << YAML::Key << "AnimationComponent"; out << YAML::BeginMap; - out << YAML::Key << "TexturePath" << YAML::Value << texturePath; - out << YAML::Key << "Columns" << YAML::Value << columns; - out << YAML::Key << "Rows" << YAML::Value << rows; + out << YAML::Key << "TextureUAID" << YAML::Value << textureUAID; + out << YAML::Key << "TexelWidth" << YAML::Value << atlas.frameWidth; + out << YAML::Key << "TexelHeight" << YAML::Value << atlas.frameHeight; out << YAML::Key << "FrameDuration" << YAML::Value << frameDuration; + out << YAML::Key << "StartFrame" << YAML::Value << startFrame; + out << YAML::Key << "EndFrame" << YAML::Value << endFrame; out << YAML::EndMap; } -void AnimationComponent::Load(const YAML::Node& node) { +void AnimationComponent::Load(const YAML::Node &node) +{ if (!node["AnimationComponent"]) return; - const auto& data = node["AnimationComponent"]; - std::string path = data["TexturePath"].as(); - int cols = data["Columns"].as(); - int rows = data["Rows"].as(); - float duration = data["FrameDuration"].as(); + const auto &data = node["AnimationComponent"]; + uint64_t uaid = data["TextureUAID"].as(); + int texelWidth = data["TexelWidth"].as(); + int texelHeight = data["TexelHeight"].as(); + float duration = data["FrameDuration"].as(); + int start = data["StartFrame"] ? data["StartFrame"].as() : 0; + int end = data["EndFrame"] ? data["EndFrame"].as() : INT_MAX; - SetTextureAtlas(path, cols, rows, duration); + SetTextureAtlas(uaid, texelWidth, texelHeight, duration, start, end); } - - diff --git a/src/src/Components/AnimationComponent.h b/src/src/Components/AnimationComponent.h index fb3fb81..47cd3ed 100644 --- a/src/src/Components/AnimationComponent.h +++ b/src/src/Components/AnimationComponent.h @@ -6,13 +6,17 @@ #include #include "../core/utils/Texture.h" #include "../core/utils/TextureAtlas.h" +#include "../core/utils/AssetManager.h" +#include "../core/utils/Logging.h" + class AnimationComponent : public Component { public: AnimationComponent(Object *owner); - void SetTextureAtlas(const std::string &path, int cols, int rows, float frameDuration); + void SetTextureAtlasPath(const std::string &path, int texelWidth, int texelHeight, float frameDuration, int startFrame = 0, int endFrame = INT_MAX); + void SetTextureAtlas(uint64_t uaid, int texelWidth, int texelHeight, float frameDuration, int startFrame = 0, int endFrame = INT_MAX); void Play(); void Stop(); @@ -25,9 +29,11 @@ public: float GetSpeed() const { return speed; } TextureAtlas *GetAtlas() { return &atlas; } + const TextureAtlas *GetAtlas() const { return &atlas; } + int GetCurrentFrame() const { return currentFrame; } - const std::string &GetTexturePath() const { return texturePath; } + uint64_t GetTextureUAID() const { return textureUAID; } float GetFrameDuration() const { return frameDuration; } void Update(float dt); @@ -36,9 +42,11 @@ public: void Save(YAML::Emitter &out) const override; void Load(const YAML::Node &node) override; -private: - std::string texturePath; + + RenderType renderType; + +private: std::shared_ptr texture; TextureAtlas atlas; @@ -46,10 +54,15 @@ private: int rows = 1; int totalFrames = 1; + int startFrame = 0; + int endFrame = 0; + float frameDuration = 0.1f; float time = 0.0f; int currentFrame = 0; bool playing = true; bool loop = true; float speed = 1.0f; + + uint64_t textureUAID = 0; }; diff --git a/src/src/Components/ParticleComponent.cpp b/src/src/Components/ParticleComponent.cpp index 1441cab..d0e9387 100644 --- a/src/src/Components/ParticleComponent.cpp +++ b/src/src/Components/ParticleComponent.cpp @@ -1,5 +1,5 @@ #include "ParticleComponent.h" -#include "../Renderer.h" // Adjust if needed +#include "../Renderer.h" #include #include @@ -55,7 +55,6 @@ void ParticleComponent::Update(float dt) particles.end()); } - void ParticleComponent::SpawnParticle() { Particle p; @@ -73,7 +72,8 @@ void ParticleComponent::SpawnParticle() particles.push_back(p); } -void ParticleComponent::Save(YAML::Emitter& out) const + +void ParticleComponent::Save(YAML::Emitter &out) const { out << YAML::BeginMap; out << YAML::Key << "type" << YAML::Value << "ParticleComponent"; @@ -90,7 +90,7 @@ void ParticleComponent::Save(YAML::Emitter& out) const out << YAML::Key << "direction" << YAML::Value << YAML::Flow << YAML::BeginSeq << settings.direction.x << settings.direction.y << YAML::EndSeq; out << YAML::Key << "spread" << YAML::Value << settings.spread; - auto writeColor = [](const Color& c, YAML::Emitter& out) + auto writeColor = [](const Color &c, YAML::Emitter &out) { out << YAML::Flow << YAML::BeginSeq << c.r << c.g << c.b << c.a << YAML::EndSeq; }; @@ -102,21 +102,22 @@ void ParticleComponent::Save(YAML::Emitter& out) const out << YAML::Key << "loop" << YAML::Value << settings.loop; out << YAML::Key << "burst" << YAML::Value << settings.burst; + out << YAML::Key << "roundness" << YAML::Value << settings.roundness; + out << YAML::EndMap; } - -void ParticleComponent::Load(const YAML::Node& node) +void ParticleComponent::Load(const YAML::Node &node) { if (!node || !node.IsMap()) return; - auto vec2 = [](const YAML::Node& n) + auto vec2 = [](const YAML::Node &n) { return Vec2(n[0].as(), n[1].as()); }; - auto color = [](const YAML::Node& n) + auto color = [](const YAML::Node &n) { return Color(n[0].as(), n[1].as(), n[2].as(), n[3].as()); }; @@ -142,4 +143,6 @@ void ParticleComponent::Load(const YAML::Node& node) settings.loop = node["loop"].as(); if (node["burst"]) settings.burst = node["burst"].as(); + if (node["roundness"]) + settings.roundness = node["roundness"].as(); } diff --git a/src/src/Components/ParticleComponent.h b/src/src/Components/ParticleComponent.h index 43db8b7..d2636ef 100644 --- a/src/src/Components/ParticleComponent.h +++ b/src/src/Components/ParticleComponent.h @@ -13,6 +13,22 @@ #include #include + +enum class ParticleShape +{ + Circle, + Square, + // Triangle, + // Line, + // Star, + // Hexagon, + // Diamond, + // Cross, + + // Outline + MAX_SHAPE +}; + struct Particle { core::types::Vec2 position; @@ -39,8 +55,11 @@ struct ParticleEmitterSettings core::types::Color endColor = {1, 1, 1, 0}; bool loop = true; bool burst = false; + + float roundness = 1.0f; // 0 = square, 1 = circle }; + class ParticleComponent : public Component { public: diff --git a/src/src/Components/SpriteComponent.cpp b/src/src/Components/SpriteComponent.cpp index 1073724..6cac848 100644 --- a/src/src/Components/SpriteComponent.cpp +++ b/src/src/Components/SpriteComponent.cpp @@ -1,81 +1,12 @@ #include "SpriteComponent.h" -#define STB_IMAGE_IMPLEMENTATION -#include -#include -#include -#include +#include "../core/utils/AssetManager.h" #include "../core/utils/Logging.h" -#include "../core/utils/utils.h" - - - - - - - - +#include SpriteComponent::SpriteComponent(Object *owner) : Component(owner) {} - - - - -unsigned int SpriteComponent::LoadTexture(const std::string& path, bool updateSize) -{ - auto [it, inserted] = textureCache.try_emplace(path, ImageCacheEntry{}); - - if (!inserted) - { - if (updateSize) - size = it->second.size; - Logger::LogDebug("Using Cached Image: '%s', Texture ID: %u", path.c_str(), it->second.textureID); - return it->second.textureID; - } - - int w, h, channels; - stbi_set_flip_vertically_on_load(false); - unsigned char* data = stbi_load(path.c_str(), &w, &h, &channels, 4); - - if (!data) - { - Logger::LogError("Failed to load image: '%s': %s", path.c_str(), stbi_failure_reason()); - textureCache.erase(it); - return 0; - } - - glm::vec2 imageSize(w, h); - if (updateSize) - size = imageSize; - - unsigned int id; - glGenTextures(1, &id); - glBindTexture(GL_TEXTURE_2D, id); - - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, data); - glGenerateMipmap(GL_TEXTURE_2D); - - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - - stbi_image_free(data); - - it->second = { id, imageSize }; - - Logger::LogDebug("Loaded Image: '%s' (%dx%d), Texture ID: %u", path.c_str(), w, h, id); - return id; -} - - - - - - - bool SpriteComponent::HasTexture() { return texture_loaded; @@ -83,22 +14,44 @@ bool SpriteComponent::HasTexture() void SpriteComponent::SetTexture(const std::string &path) { - if (path.empty()) - return; - texturePath = path; - textureID = LoadTexture(path, true); - if (textureID != 0) - { - texture_loaded = true; - } + if (path.empty()) return; + + AssetManager::LoadAssetAsync(path, AssetType::Image); + const auto* asset = AssetManager::GetAssetByPath(path); + if (asset) + SetTexture(asset->uaid); } void SpriteComponent::SetNormalMap(const std::string &path) { - if (path.empty()) - return; - normalMapPath = path; - normalMapID = LoadTexture(path, false); + if (path.empty()) return; + + AssetManager::LoadAssetAsync(path, AssetType::Image); + const auto* asset = AssetManager::GetAssetByPath(path); + if (asset) + SetNormalMap(asset->uaid); +} + +void SpriteComponent::SetTexture(uint64_t uaid) +{ + textureUAID = uaid; + const auto* asset = AssetManager::GetAssetByID(uaid); + if (asset && asset->loaded) + { + textureID = asset->textureID; + size = asset->size; + texture_loaded = true; + } +} + +void SpriteComponent::SetNormalMap(uint64_t uaid) +{ + normalMapUAID = uaid; + const auto* asset = AssetManager::GetAssetByID(uaid); + if (asset && asset->loaded) + { + normalMapID = asset->textureID; + } } unsigned int SpriteComponent::GetTextureID() const @@ -111,62 +64,42 @@ unsigned int SpriteComponent::GetNormalMapID() const return normalMapID; } -std::string SpriteComponent::GetTexturePath() const +uint64_t SpriteComponent::GetTextureUAID() const { - return texturePath; + return textureUAID; } -std::string SpriteComponent::GetNormalMapPath() const +uint64_t SpriteComponent::GetNormalMapUAID() const { - return normalMapPath; + return normalMapUAID; } void SpriteComponent::Save(YAML::Emitter &out) const { out << YAML::BeginMap; out << YAML::Key << "type" << YAML::Value << "SpriteComponent"; - out << YAML::Key << "texture" << YAML::Value << texturePath; - out << YAML::Key << "normalMap" << YAML::Value << normalMapPath; + out << YAML::Key << "texture" << YAML::Value << textureUAID; + out << YAML::Key << "normalMap" << YAML::Value << normalMapUAID; out << YAML::Key << "renderType" << YAML::Value << (renderType == RenderType::Lit ? "Lit" : "Unlit"); out << YAML::EndMap; } - void SpriteComponent::Load(const YAML::Node& node) { try { - if (!node["texture"]) - { - RecoverableError("Missing 'texture' key in SpriteComponent YAML node", Create::Exceptions::MissingField).Handle(); - } - else if (!node["texture"].IsScalar()) - { - RecoverableError("'texture' field must be a string", Create::Exceptions::InvalidFormat).Handle(); - } - else if (!node["texture"].as().empty()) - { - SetTexture(node["texture"].as()); - } + if (node["texture"]) + SetTexture(node["texture"].as()); - if (!node["normalMap"]) - { - RecoverableError("Missing 'normalMap' key in SpriteComponent YAML node", Create::Exceptions::MissingField).Handle(); - } - else if (!node["normalMap"].IsScalar()) - { - RecoverableError("'normalMap' field must be a string", Create::Exceptions::InvalidFormat).Handle(); - } - else if (!node["normalMap"].as().empty()) - { - SetNormalMap(node["normalMap"].as()); - } + if (node["normalMap"]) + SetNormalMap(node["normalMap"].as()); if (node["renderType"] && node["renderType"].IsScalar()) { std::string typeStr = node["renderType"].as(); if (typeStr == "Lit") renderType = RenderType::Lit; else if (typeStr == "Unlit") renderType = RenderType::Unlit; else - RecoverableError("Invalid 'renderType' value in SpriteComponent: " + typeStr, Create::Exceptions::InvalidFormat).Handle(); + RecoverableError("Invalid 'renderType' value in SpriteComponent: " + typeStr, + Create::Exceptions::InvalidFormat).Handle(); } } catch (const YAML::Exception& e) { diff --git a/src/src/Components/SpriteComponent.h b/src/src/Components/SpriteComponent.h index e3ce344..2ea7bdd 100644 --- a/src/src/Components/SpriteComponent.h +++ b/src/src/Components/SpriteComponent.h @@ -3,54 +3,42 @@ #include "Component.h" #include #include - - - - +#include "../core/utils/AssetManager.h" +#include "../core/utils/Texture.h" class SpriteComponent : public Component { public: SpriteComponent(Object* owner); - enum class RenderType { - Unlit, - Lit - }; - - void SetTexture(const std::string& path); + void SetTexture(uint64_t uaid); void SetNormalMap(const std::string& path); + void SetNormalMap(uint64_t uaid); unsigned int GetTextureID() const; unsigned int GetNormalMapID() const; - - std::string GetTexturePath() const; - std::string GetNormalMapPath() const; + uint64_t GetTextureUAID() const; + uint64_t GetNormalMapUAID() const; bool HasTexture(); - RenderType GetRenderType() const { return renderType; } void SetRenderType(RenderType type) { renderType = type; } virtual glm::vec2 GetSize() const { return size; } - virtual std::string GetName() const override { return "SpriteComponent"; } virtual void Save(YAML::Emitter& out) const override; virtual void Load(const YAML::Node& node) override; - - private: glm::vec2 size = { 64, 64 }; - std::string texturePath; - std::string normalMapPath; RenderType renderType = RenderType::Lit; + + uint64_t textureUAID = 0; + uint64_t normalMapUAID = 0; + unsigned int textureID = 0; unsigned int normalMapID = 0; bool texture_loaded = false; - unsigned int LoadTexture(const std::string& path, bool updateSize); - - }; diff --git a/src/src/Engine.cpp b/src/src/Engine.cpp index a651768..2b2a0a3 100644 --- a/src/src/Engine.cpp +++ b/src/src/Engine.cpp @@ -10,7 +10,6 @@ #include "components/ParticleComponent.h" #include "components/AnimationComponent.h" - #include "core/utils/FileDialog.h" #include "core/utils/Logging.h" @@ -489,7 +488,7 @@ void Engine::Init() // auto sprite = obj->AddComponent(); // sprite->SetTexture("C:/Users/spenc/OneDrive/Pictures/textures/ganges_river_pebbles_diff_1k.png"); // sprite->SetNormalMap("C:/Users/spenc/OneDrive/Pictures/textures/ganges_river_pebbles_nor_gl_1k.png"); - // sprite->SetRenderType(SpriteComponent::RenderType::Lit); + // sprite->SetRenderType(RenderType::Lit); // // objects.push_back(obj); // } @@ -515,22 +514,26 @@ void Engine::Init() Logger::LogVerbose("Resverving Objects"); m_toDraw.reserve(1024); - m_scriptUpdates.reserve(256); + m_scriptUpdates.reserve(10); m_collectStack.reserve(1024); m_physicsUpdates.reserve(1024); - m_particleUpdates.reserve(1024); + m_particleUpdates.reserve(100); + m_animationsUpdates.reserve(100); Logger::LogInfo("Initialized Engine"); } void Engine::collectObjects(bool playing, const glm::vec2 &camPos, float camZoom) { + + m_activeCamera = nullptr; + m_toDraw.clear(); m_scriptUpdates.clear(); + m_animationsUpdates.clear(); m_collectStack.clear(); - m_activeCamera = nullptr; m_physicsUpdates.clear(); - m_particleUpdates.clear(); // <-- Add this + m_particleUpdates.clear(); const glm::vec2 screenSize = glm::vec2(Renderer::GetSize()); @@ -566,6 +569,8 @@ void Engine::collectObjects(bool playing, const glm::vec2 &camPos, float camZoom if (auto particles = obj->GetComponent()) m_particleUpdates.push_back(particles.get()); + if (auto animator = obj->GetComponent()) + m_animationsUpdates.push_back(animator.get()); if (playing) { @@ -696,7 +701,6 @@ void Engine::Run() ImGui::Checkbox("Profiler", &g_engineConfig.settings.show_profiler_window); ImGui::Checkbox("Assets", &g_engineConfig.settings.show_asset_window); - ImGui::EndMenu(); } @@ -862,7 +866,6 @@ void Engine::Run() m_OnUpdateCalls = 0; - if (!g_engineConfig.settings.profile_editor) { profiler.BeginFrame(); @@ -888,6 +891,15 @@ void Engine::Run() } profiler.EndSection(); + profiler.BeginSection("Animations"); + for (auto *animation : m_animationsUpdates) + { + profiler.BeginSection("Object: " + animation->GetOwner()->GetName()); + animation->Update(deltaTime); + profiler.EndSection(); + } + profiler.EndSection(); + profiler.EndSection(); profiler.BeginSection("Render"); @@ -895,22 +907,21 @@ void Engine::Run() { const core::types::Vec2 worldPos = obj->GetWorldPosition(); - if (auto spritePtr = obj->GetComponent()) + if (auto sprite = obj->GetComponent()) { profiler.BeginSection("Draw Sprite: " + obj->GetName()); - Renderer::DrawSprite(spritePtr.get(), worldPos, cameraZoom, cameraPos); + Renderer::DrawSprite(sprite.get(), worldPos, cameraZoom, cameraPos); profiler.EndSection(); } - if (auto animator = obj->GetComponent()) { - profiler.BeginSection("Draw Animation: " + obj->GetName()); - - Renderer::DrawTextureAtlas(animator->GetAtlas(), animator->GetCurrentFrame(), obj->GetWorldPosition(), obj->GetWorldRotation(), 1.0f); - + if (auto animator = obj->GetComponent()) + { + profiler.BeginSection("Draw Animator: " + obj->GetName()); + + Renderer::DrawAnimator(animator.get(), worldPos, cameraZoom, cameraPos); + profiler.EndSection(); } - - if (auto particle = obj->GetComponent()) { @@ -926,7 +937,7 @@ void Engine::Run() core::types::Vec2 pWorld = p.position + particle->GetOwner()->GetWorldPosition(); core::types::Vec2 size = core::types::Vec2(p.size, p.size); - Renderer::BatchQuad(pWorld, size, p.rotation, color, cameraPos, cameraZoom); + Renderer::BatchQuad(pWorld, size, p.rotation, color, cameraPos, cameraZoom, settings.roundness); } profiler.EndSection(); @@ -1117,7 +1128,6 @@ void Engine::SaveScene(const std::string &path) for (int i = 0; i < SHA256_DIGEST_LENGTH; ++i) hashHex << std::hex << std::setw(2) << std::setfill('0') << static_cast(hash[i]); - // Build final full YAML output out << YAML::BeginMap; out << YAML::Key << "engine_version" << YAML::Value << g_engineConfig.version; out << YAML::Key << "scene_name" << YAML::Value << std::filesystem::path(path).stem().string(); @@ -1131,13 +1141,13 @@ void Engine::SaveScene(const std::string &path) out << YAML::Key << "brightness" << YAML::Value << Renderer::GetColorCorrection()->brightness; out << YAML::Key << "saturation" << YAML::Value << Renderer::GetColorCorrection()->saturation; out << YAML::Key << "gamma" << YAML::Value << Renderer::GetColorCorrection()->gamma; - out << YAML::Key << "bloom" << YAML::Value << Renderer::GetColorCorrection()->bloom; out << YAML::Key << "intensity" << YAML::Value << Renderer::GetColorCorrection()->intensity; out << YAML::Key << "threshold" << YAML::Value << Renderer::GetColorCorrection()->threshold; - out << YAML::EndMap; + AssetManager::Save(out); + out << YAML::EndMap; std::ofstream file(path); @@ -1147,7 +1157,6 @@ void Engine::SaveScene(const std::string &path) void Engine::LoadScene(const std::string &path) { Logger::LogDebug("[LoadScene] Reading Scene File."); - YAML::Node root = YAML::LoadFile(path); Logger::LogDebug("[LoadScene] Verifying Scene"); @@ -1169,6 +1178,12 @@ void Engine::LoadScene(const std::string &path) Logger::LogWarning("[LoadScene] Scene hash does not match! File may be corrupted or tampered."); } + if (root["Assets"]) + { + Logger::LogVerbose("[LoadScene] Loading Assets"); + AssetManager::Load(root["Assets"]); + } + Logger::LogDebug("[LoadScene] Reseting Scene."); objects.clear(); @@ -1196,7 +1211,6 @@ void Engine::LoadScene(const std::string &path) cc->saturation = data["saturation"].as(); if (data["gamma"]) cc->gamma = data["gamma"].as(); - if (data["bloom"]) cc->bloom = data["bloom"].as(); if (data["intensity"]) @@ -1225,18 +1239,19 @@ void Engine::SaveState() out << YAML::Key << "brightness" << YAML::Value << Renderer::GetColorCorrection()->brightness; out << YAML::Key << "saturation" << YAML::Value << Renderer::GetColorCorrection()->saturation; out << YAML::Key << "gamma" << YAML::Value << Renderer::GetColorCorrection()->gamma; - out << YAML::Key << "bloom" << YAML::Value << Renderer::GetColorCorrection()->bloom; out << YAML::Key << "intensity" << YAML::Value << Renderer::GetColorCorrection()->intensity; out << YAML::Key << "threshold" << YAML::Value << Renderer::GetColorCorrection()->threshold; - out << YAML::EndMap; + AssetManager::Save(out); + out << YAML::EndMap; savedStateYAML = out.c_str(); Logger::LogVerbose("[SaveState] Scene serialized (%zu bytes)", savedStateYAML.size()); } + void Engine::LoadState() { if (savedStateYAML.empty()) @@ -1256,6 +1271,12 @@ void Engine::LoadState() return; } + if (root["Assets"]) + { + Logger::LogVerbose("[LoadState] Loading Assets"); + AssetManager::Load(root["Assets"]); + } + objects.clear(); const auto &objectArray = root["objects"]; @@ -1263,7 +1284,6 @@ void Engine::LoadState() { auto obj = std::make_shared("[DefaultObject]"); obj->Load(node); - objects.push_back(obj); } @@ -1281,7 +1301,6 @@ void Engine::LoadState() cc->saturation = data["saturation"].as(); if (data["gamma"]) cc->gamma = data["gamma"].as(); - if (data["bloom"]) cc->bloom = data["bloom"].as(); if (data["intensity"]) diff --git a/src/src/Engine.h b/src/src/Engine.h index 818f422..2996911 100644 --- a/src/src/Engine.h +++ b/src/src/Engine.h @@ -10,6 +10,7 @@ class Object; class ScriptComponent; class PhysicsComponent; class ParticleComponent; +class AnimationComponent; class Engine { @@ -36,6 +37,7 @@ private: std::vector m_toDraw; std::vector m_scriptUpdates; + std::vector m_animationsUpdates; int m_OnUpdateCalls; std::vector> m_collectStack; diff --git a/src/src/Renderer.cpp b/src/src/Renderer.cpp index 5b2a539..fe3e0a7 100644 --- a/src/src/Renderer.cpp +++ b/src/src/Renderer.cpp @@ -77,15 +77,16 @@ struct BatchedSprite glm::vec4 texCoords; GLuint textureID; GLuint normalMapID; - SpriteComponent::RenderType renderType; + RenderType renderType; SpriteComponent *sprite; }; struct SortedDrawEntry { BatchedSprite sprite; - Shader *shader; - bool useLighting; + Shader *shader = nullptr; + bool useLighting = true; + bool usesUV = false; }; std::vector s_LightUniforms; @@ -162,25 +163,26 @@ void Renderer::InitQuadBatch() std::size_t offset = 0; - glEnableVertexAttribArray(1); // pos - glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, sizeof(QuadInstance), (void *)(offset)); + glEnableVertexAttribArray(1); + glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, sizeof(QuadInstance), (void *)offsetof(QuadInstance, screenPos)); glVertexAttribDivisor(1, 1); - offset += sizeof(glm::vec2); - glEnableVertexAttribArray(2); // size - glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, sizeof(QuadInstance), (void *)(offset)); + glEnableVertexAttribArray(2); + glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, sizeof(QuadInstance), (void *)offsetof(QuadInstance, size)); glVertexAttribDivisor(2, 1); - offset += sizeof(glm::vec2); - glEnableVertexAttribArray(3); // rotation - glVertexAttribPointer(3, 1, GL_FLOAT, GL_FALSE, sizeof(QuadInstance), (void *)(offset)); + glEnableVertexAttribArray(3); + glVertexAttribPointer(3, 1, GL_FLOAT, GL_FALSE, sizeof(QuadInstance), (void *)offsetof(QuadInstance, rotation)); glVertexAttribDivisor(3, 1); - offset += sizeof(float); - glEnableVertexAttribArray(4); // color - glVertexAttribPointer(4, 4, GL_FLOAT, GL_FALSE, sizeof(QuadInstance), (void *)(offset)); + glEnableVertexAttribArray(4); + glVertexAttribPointer(4, 4, GL_FLOAT, GL_FALSE, sizeof(QuadInstance), (void *)offsetof(QuadInstance, color)); glVertexAttribDivisor(4, 1); + glEnableVertexAttribArray(5); + glVertexAttribPointer(5, 1, GL_FLOAT, GL_FALSE, sizeof(QuadInstance), (void *)offsetof(QuadInstance, roundness)); + glVertexAttribDivisor(5, 1); + glBindVertexArray(0); } @@ -525,7 +527,14 @@ void Renderer::DrawQuad(const core::types::Vec2 &pos, const core::types::Vec2 &s s_QuadBatch.push_back({pos, size, rotation, color}); } -void Renderer::BatchQuad(const core::types::Vec2 &worldPos, const core::types::Vec2 &size, float rotation, const core::types::Color &color, const core::types::Vec2 &cameraPos, float zoom) + +void Renderer::BatchQuad(const core::types::Vec2 &worldPos, + const core::types::Vec2 &size, + float rotation, + const core::types::Color &color, + const core::types::Vec2 &cameraPos, + float zoom, + float isCircle) { if (s_QuadBatch.size() >= MAX_QUADS) FlushQuads(); @@ -533,7 +542,16 @@ void Renderer::BatchQuad(const core::types::Vec2 &worldPos, const core::types::V core::types::Vec2 screenPos = (worldPos - cameraPos) * zoom + core::types::Vec2(width * 0.5f, height * 0.5f); core::types::Vec2 finalSize = size * zoom; - s_QuadBatch.push_back({screenPos, finalSize, rotation, color}); + s_QuadBatch.push_back({screenPos, finalSize, rotation, color, isCircle}); +} + +void Renderer::BatchCircle(const core::types::Vec2 &worldPos, + const core::types::Vec2 &size, + const core::types::Color &color, + const core::types::Vec2 &cameraPos, + float zoom) +{ + BatchQuad(worldPos, size, 0.0f, color, cameraPos, zoom, 1.0f); } void Renderer::DrawSprite(SpriteComponent *sprite, const glm::vec2 &pos, float zoom, glm::vec2 &CameraPos) @@ -558,7 +576,7 @@ void Renderer::DrawSprite(SpriteComponent *sprite, const glm::vec2 &pos, float z SortedDrawEntry drawEntry; drawEntry.sprite = entry; - drawEntry.shader = (g_engineConfig.settings.lighting_enabled && entry.renderType == SpriteComponent::RenderType::Lit) + drawEntry.shader = (g_engineConfig.settings.lighting_enabled && entry.renderType == RenderType::Lit) ? &spriteShader : &unlitShader; drawEntry.useLighting = (drawEntry.shader == &spriteShader); @@ -566,7 +584,6 @@ void Renderer::DrawSprite(SpriteComponent *sprite, const glm::vec2 &pos, float z sortedDrawList.push_back(drawEntry); } - void Renderer::DrawTextureAtlas(const TextureAtlas *atlas, int index, const core::types::Vec2 &pos, float rotationDeg, float zoom) { PROFILE_DEEP_SCOPE("DrawTextureAtlas"); @@ -579,7 +596,10 @@ void Renderer::DrawTextureAtlas(const TextureAtlas *atlas, int index, const core const core::types::Vec2 uvMax = uvMin + atlas->GetFrameSizeUV(); glm::vec2 screenPos = pos * zoom + glm::vec2(width, height) * 0.5f; - glm::vec2 finalSize = glm::vec2(1.0f) * zoom; + + glm::vec2 frameSize = atlas->GetFrameSizeUV() * tex->GetSize(); + + glm::vec2 finalSize = frameSize * zoom; BatchedSprite entry; entry.screenPos = screenPos; @@ -587,7 +607,7 @@ void Renderer::DrawTextureAtlas(const TextureAtlas *atlas, int index, const core entry.rotationRad = glm::radians(rotationDeg); entry.textureID = tex->GetID(); entry.normalMapID = defaultNormalMap; - entry.renderType = SpriteComponent::RenderType::Unlit; // no lighting for raw atlas drawing + entry.renderType = RenderType::Lit; entry.sprite = nullptr; entry.texCoords = glm::vec4(uvMin.x, uvMin.y, uvMax.x, uvMax.y); @@ -595,10 +615,51 @@ void Renderer::DrawTextureAtlas(const TextureAtlas *atlas, int index, const core drawEntry.sprite = entry; drawEntry.shader = &unlitShader; drawEntry.useLighting = false; + drawEntry.usesUV = true; // <- Important! sortedDrawList.push_back(drawEntry); } +void Renderer::DrawAnimator(const AnimationComponent *anim, const core::types::Vec2 &worldPos, float zoom, const core::types::Vec2 &cameraPos) +{ + PROFILE_DEEP_SCOPE("Renderer::DrawAnimator"); + + if (!anim || !anim->GetAtlas() || !anim->GetAtlas()->texture) + return; + + const TextureAtlas *atlas = anim->GetAtlas(); + int frameIndex = anim->GetCurrentFrame(); + + if (frameIndex >= atlas->GetTotalFrames()) + return; + + const auto &tex = atlas->texture; + core::types::Vec2 uvMin = atlas->GetFrameUV(frameIndex); + core::types::Vec2 uvMax = uvMin + atlas->GetFrameSizeUV(); + core::types::Vec2 texSize = tex->GetSize(); + + glm::vec2 screenPos = (worldPos - cameraPos) * zoom + glm::vec2(width, height) * 0.5f; + glm::vec2 frameSize = atlas->GetFrameSizeUV() * texSize; + glm::vec2 finalSize = frameSize * zoom; + + BatchedSprite entry; + entry.screenPos = screenPos; + entry.size = finalSize; + entry.rotationRad = 0.0f; + entry.textureID = tex->GetID(); + entry.normalMapID = defaultNormalMap; + entry.renderType = anim->renderType; + entry.sprite = nullptr; + entry.texCoords = glm::vec4(uvMin.x, uvMin.y, uvMax.x, uvMax.y); + + SortedDrawEntry drawEntry; + drawEntry.sprite = entry; + drawEntry.shader = &unlitShader; + drawEntry.useLighting = false; + drawEntry.usesUV = true; + + sortedDrawList.push_back(drawEntry); +} void Renderer::FlushQuads() { PROFILE_ENGINE_SCOPE("Renderer::FlushQuads"); @@ -614,16 +675,8 @@ void Renderer::FlushQuads() glBindVertexArray(s_QuadVAO); glBindBuffer(GL_ARRAY_BUFFER, s_QuadInstanceVBO); - { - PROFILE_DEEP_SCOPE("Upload"); - s_UnlitQuadShader.Use(); - s_UnlitQuadShader.SetVec2("uScreen", glm::vec2(width, height)); - - glBindVertexArray(s_QuadVAO); - // Write directly to mapped buffer - std::memcpy(s_QuadMappedPtr, s_QuadBatch.data(), s_QuadBatch.size() * sizeof(QuadInstance)); - } + std::memcpy(s_QuadMappedPtr, s_QuadBatch.data(), s_QuadBatch.size() * sizeof(QuadInstance)); } { @@ -685,13 +738,26 @@ void Renderer::FlushSprites() } } - // Uniforms + // Common uniforms currentShader->SetVec2("uPos", entry.sprite.screenPos); currentShader->SetVec2("uSize", entry.sprite.size); currentShader->SetFloat("uRotation", entry.sprite.rotationRad); currentShader->SetInt("uTex", 0); - // Textures + // Set UVs if applicable + if (entry.usesUV) + { + currentShader->SetVec2("uUVMin", glm::vec2(entry.sprite.texCoords.x, entry.sprite.texCoords.y)); + currentShader->SetVec2("uUVMax", glm::vec2(entry.sprite.texCoords.z, entry.sprite.texCoords.w)); + } + else + { + // Full UV range fallback + currentShader->SetVec2("uUVMin", glm::vec2(0.0f)); + currentShader->SetVec2("uUVMax", glm::vec2(1.0f)); + } + + // Bind textures glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, entry.sprite.textureID); diff --git a/src/src/Renderer.h b/src/src/Renderer.h index 18db759..40c9c09 100644 --- a/src/src/Renderer.h +++ b/src/src/Renderer.h @@ -6,6 +6,9 @@ #include "Components/TilemapComponent.h" #include "Components/SpriteComponent.h" +#include "Components/SpriteComponent.h" +#include "Components/AnimationComponent.h" + #include "core/utils/EngineConfig.h" #include "utils/Shader.h" #include "core/utils/Profiler.h" @@ -20,7 +23,7 @@ struct ColorCorrection float gamma = 1.0f; bool bloom = true; - float threshold = 0.2f; + float threshold = 1.0f; float intensity = 1.2f; void Upload(Shader &shader) const @@ -41,10 +44,11 @@ struct Light struct QuadInstance { - core::types::Vec2 pos; + core::types::Vec2 screenPos; core::types::Vec2 size; float rotation; core::types::Color color; + float roundness = 0.0f; }; class Renderer @@ -80,10 +84,24 @@ public: static void InitQuadBatch(); static void DrawQuad(const core::types::Vec2 &pos, const core::types::Vec2 &size, float rotation, const core::types::Color &color); - static void BatchQuad(const core::types::Vec2 &worldPos, const core::types::Vec2 &size, float rotation, const core::types::Color &color, const core::types::Vec2 &cameraPos, float zoom); + static void BatchQuad(const core::types::Vec2 &worldPos, + const core::types::Vec2 &size, + float rotation, + const core::types::Color &color, + const core::types::Vec2 &cameraPos, + float zoom, + float isCircle = 0.0f); + + static void BatchCircle(const core::types::Vec2 &worldPos, + const core::types::Vec2 &size, + const core::types::Color &color, + const core::types::Vec2 &cameraPos, + float zoom); static void DrawTextureAtlas(const TextureAtlas *atlas, int index, const core::types::Vec2 &pos, float rotationDeg, float zoom); + static void DrawAnimator(const AnimationComponent *anim, const core::types::Vec2 &worldPos, float zoom, const core::types::Vec2 &cameraPos); + static void FlushQuads(); private: diff --git a/src/src/core/types/vec2.h b/src/src/core/types/vec2.h index ebb87f0..ae84184 100644 --- a/src/src/core/types/vec2.h +++ b/src/src/core/types/vec2.h @@ -9,62 +9,40 @@ namespace core namespace types { + struct Vec2i; + struct Vec2 { float x{0}, y{0}; - // Constructors Vec2() = default; Vec2(float x, float y) : x(x), y(y) {} Vec2(float v) : x(v), y(v) {} Vec2(const glm::vec2 &v) : x(v.x), y(v.y) {} + Vec2(const Vec2i &v); - // Conversion to glm operator glm::vec2() const { return {x, y}; } - // Arithmetic operators Vec2 operator+(const Vec2 &rhs) const { return {x + rhs.x, y + rhs.y}; } Vec2 operator-(const Vec2 &rhs) const { return {x - rhs.x, y - rhs.y}; } Vec2 operator*(float scalar) const { return {x * scalar, y * scalar}; } Vec2 operator/(float scalar) const { return {x / scalar, y / scalar}; } - Vec2 &operator+=(const Vec2 &rhs) - { - x += rhs.x; - y += rhs.y; - return *this; - } - Vec2 &operator-=(const Vec2 &rhs) - { - x -= rhs.x; - y -= rhs.y; - return *this; - } - Vec2 &operator*=(float scalar) - { - x *= scalar; - y *= scalar; - return *this; - } - Vec2 &operator/=(float scalar) - { - x /= scalar; - y /= scalar; - return *this; - } + Vec2 operator*(const Vec2 &rhs) const { return {x * rhs.x, y * rhs.y}; } + + Vec2 &operator+=(const Vec2 &rhs) { x += rhs.x; y += rhs.y; return *this; } + Vec2 &operator-=(const Vec2 &rhs) { x -= rhs.x; y -= rhs.y; return *this; } + Vec2 &operator*=(float scalar) { x *= scalar; y *= scalar; return *this; } + Vec2 &operator/=(float scalar) { x /= scalar; y /= scalar; return *this; } - // Unary operators Vec2 operator-() const { return {-x, -y}; } - // Comparison bool operator==(const Vec2 &rhs) const { return x == rhs.x && y == rhs.y; } bool operator!=(const Vec2 &rhs) const { return !(*this == rhs); } - // Length float Length() const { return std::sqrt(x * x + y * y); } float LengthSquared() const { return x * x + y * y; } - // Normalization Vec2 Normalized() const { float len = Length(); @@ -81,40 +59,61 @@ namespace core } } - // Dot product float Dot(const Vec2 &rhs) const { return x * rhs.x + y * rhs.y; } - // Clamp void Clamp(const Vec2 &min, const Vec2 &max) { x = std::max(min.x, std::min(x, max.x)); y = std::max(min.y, std::min(y, max.y)); } - // Lerp static Vec2 Lerp(const Vec2 &a, const Vec2 &b, float t) { return a + (b - a) * t; } - // Distance static float Distance(const Vec2 &a, const Vec2 &b) { return (a - b).Length(); } - // Serialization helpers (optional) friend std::ostream &operator<<(std::ostream &os, const Vec2 &v) { return os << "(" << v.x << ", " << v.y << ")"; } }; - // Scalar * Vec2 support - inline Vec2 operator*(float scalar, const Vec2 &v) + struct Vec2i { - return v * scalar; - } + int x{0}, y{0}; + + Vec2i() = default; + Vec2i(int x, int y) : x(x), y(y) {} + Vec2i(int v) : x(v), y(v) {} + Vec2i(const Vec2 &v) : x(static_cast(v.x)), y(static_cast(v.y)) {} + + Vec2i operator+(const Vec2i &rhs) const { return {x + rhs.x, y + rhs.y}; } + Vec2i operator-(const Vec2i &rhs) const { return {x - rhs.x, y - rhs.y}; } + Vec2i operator*(int scalar) const { return {x * scalar, y * scalar}; } + Vec2i operator/(int scalar) const { return {x / scalar, y / scalar}; } + + Vec2 operator*(const Vec2 &rhs) const { return Vec2(x * rhs.x, y * rhs.y); } + + Vec2i &operator+=(const Vec2i &rhs) { x += rhs.x; y += rhs.y; return *this; } + Vec2i &operator-=(const Vec2i &rhs) { x -= rhs.x; y -= rhs.y; return *this; } + Vec2i &operator*=(int scalar) { x *= scalar; y *= scalar; return *this; } + Vec2i &operator/=(int scalar) { x /= scalar; y /= scalar; return *this; } + + bool operator==(const Vec2i &rhs) const { return x == rhs.x && y == rhs.y; } + bool operator!=(const Vec2i &rhs) const { return !(*this == rhs); } + + friend std::ostream &operator<<(std::ostream &os, const Vec2i &v) + { + return os << "(" << v.x << ", " << v.y << ")"; + } + }; + + inline Vec2 operator*(float scalar, const Vec2 &v) { return v * scalar; } } // namespace types -} // namespace core +} // namespace core \ No newline at end of file diff --git a/src/src/core/types/vector.h b/src/src/core/types/vector.h index 37ef006..e721b85 100644 --- a/src/src/core/types/vector.h +++ b/src/src/core/types/vector.h @@ -1,167 +1,167 @@ -#pragma once -#include -#include -#include -#include -#include -#include -#include - -#ifndef FV_ASSERT -#define FV_ASSERT(cond) assert(cond) -#endif - -template -class FastVector { - using StorageT = typename std::aligned_storage::type; - - StorageT sbo_[SBO_CAP]; - T* data_ = reinterpret_cast(sbo_); - size_t size_ = 0; - size_t capacity_ = SBO_CAP; - bool heapAllocated_ = false; - - inline void reallocate(size_t newCap) { - T* newData = reinterpret_cast(std::malloc(newCap * sizeof(T))); - if (!newData) std::abort(); - - if constexpr (std::is_trivially_copyable_v) { - std::memcpy(newData, data_, size_ * sizeof(T)); - } else { - std::uninitialized_copy(data_, data_ + size_, newData); - std::destroy(data_, data_ + size_); - } - - if (heapAllocated_) std::free(data_); - data_ = newData; - capacity_ = newCap; - heapAllocated_ = true; - } - -public: - inline FastVector() = default; - - inline ~FastVector() { - std::destroy(data_, data_ + size_); - if (heapAllocated_) std::free(data_); - } - - // Copy constructor - FastVector(const FastVector& other) { - reserve(other.size_); - if constexpr (std::is_trivially_copyable_v) { - std::memcpy(data_, other.data_, other.size_ * sizeof(T)); - } else { - std::uninitialized_copy(other.data_, other.data_ + other.size_, data_); - } - size_ = other.size_; - } - - // Move constructor - FastVector(FastVector&& other) noexcept { - if (other.heapAllocated_) { - data_ = other.data_; - size_ = other.size_; - capacity_ = other.capacity_; - heapAllocated_ = true; - } else { - std::uninitialized_move(other.data_, other.data_ + other.size_, data_); - } - other.data_ = reinterpret_cast(other.sbo_); - other.size_ = 0; - other.capacity_ = SBO_CAP; - other.heapAllocated_ = false; - } - - // Copy assignment - FastVector& operator=(const FastVector& other) { - if (this != &other) { - clear(); - reserve(other.size_); - if constexpr (std::is_trivially_copyable_v) { - std::memcpy(data_, other.data_, other.size_ * sizeof(T)); - } else { - std::uninitialized_copy(other.data_, other.data_ + other.size_, data_); - } - size_ = other.size_; - } - return *this; - } - - // Move assignment - FastVector& operator=(FastVector&& other) noexcept { - if (this != &other) { - clear(); - if (heapAllocated_) std::free(data_); - - if (other.heapAllocated_) { - data_ = other.data_; - size_ = other.size_; - capacity_ = other.capacity_; - heapAllocated_ = true; - } else { - std::uninitialized_move(other.data_, other.data_ + other.size_, data_); - } - - other.data_ = reinterpret_cast(other.sbo_); - other.size_ = 0; - other.capacity_ = SBO_CAP; - other.heapAllocated_ = false; - } - return *this; - } - - inline void push_back(const T& val) { - if (size_ == capacity_) reallocate(capacity_ * 2); - new (data_ + size_) T(val); - ++size_; - } - - inline void push_back(T&& val) { - if (size_ == capacity_) reallocate(capacity_ * 2); - new (data_ + size_) T(std::move(val)); - ++size_; - } - - inline void pop_back() { - FV_ASSERT(size_ > 0); - --size_; - std::destroy_at(data_ + size_); - } - - inline void clear() { - std::destroy(data_, data_ + size_); - size_ = 0; - } - - inline void reserve(size_t newCap) { - if (newCap > capacity_) reallocate(newCap); - } - - inline void resize(size_t newSize) { - if (newSize > capacity_) reallocate(newSize); - if (newSize > size_) { - std::uninitialized_value_construct(data_ + size_, data_ + newSize); - } else { - std::destroy(data_ + newSize, data_ + size_); - } - size_ = newSize; - } - - inline T& operator[](size_t i) { - FV_ASSERT(i < size_); - return data_[i]; - } - - inline const T& operator[](size_t i) const { - FV_ASSERT(i < size_); - return data_[i]; - } - - inline T* data() { return data_; } - inline const T* data() const { return data_; } - - inline size_t size() const { return size_; } - inline size_t capacity() const { return capacity_; } - inline bool empty() const { return size_ == 0; } -}; +//#pragma once +//#include +//#include +//#include +//#include +//#include +//#include +//#include +// +//#ifndef FV_ASSERT +//#define FV_ASSERT(cond) assert(cond) +//#endif +// +//template +//class FastVector { +// using StorageT = typename std::aligned_storage::type; +// +// StorageT sbo_[SBO_CAP]; +// T* data_ = reinterpret_cast(sbo_); +// size_t size_ = 0; +// size_t capacity_ = SBO_CAP; +// bool heapAllocated_ = false; +// +// inline void reallocate(size_t newCap) { +// T* newData = reinterpret_cast(std::malloc(newCap * sizeof(T))); +// if (!newData) std::abort(); +// +// if constexpr (std::is_trivially_copyable_v) { +// std::memcpy(newData, data_, size_ * sizeof(T)); +// } else { +// std::uninitialized_copy(data_, data_ + size_, newData); +// std::destroy(data_, data_ + size_); +// } +// +// if (heapAllocated_) std::free(data_); +// data_ = newData; +// capacity_ = newCap; +// heapAllocated_ = true; +// } +// +//public: +// inline FastVector() = default; +// +// inline ~FastVector() { +// std::destroy(data_, data_ + size_); +// if (heapAllocated_) std::free(data_); +// } +// +// // Copy constructor +// FastVector(const FastVector& other) { +// reserve(other.size_); +// if constexpr (std::is_trivially_copyable_v) { +// std::memcpy(data_, other.data_, other.size_ * sizeof(T)); +// } else { +// std::uninitialized_copy(other.data_, other.data_ + other.size_, data_); +// } +// size_ = other.size_; +// } +// +// // Move constructor +// FastVector(FastVector&& other) noexcept { +// if (other.heapAllocated_) { +// data_ = other.data_; +// size_ = other.size_; +// capacity_ = other.capacity_; +// heapAllocated_ = true; +// } else { +// std::uninitialized_move(other.data_, other.data_ + other.size_, data_); +// } +// other.data_ = reinterpret_cast(other.sbo_); +// other.size_ = 0; +// other.capacity_ = SBO_CAP; +// other.heapAllocated_ = false; +// } +// +// // Copy assignment +// FastVector& operator=(const FastVector& other) { +// if (this != &other) { +// clear(); +// reserve(other.size_); +// if constexpr (std::is_trivially_copyable_v) { +// std::memcpy(data_, other.data_, other.size_ * sizeof(T)); +// } else { +// std::uninitialized_copy(other.data_, other.data_ + other.size_, data_); +// } +// size_ = other.size_; +// } +// return *this; +// } +// +// // Move assignment +// FastVector& operator=(FastVector&& other) noexcept { +// if (this != &other) { +// clear(); +// if (heapAllocated_) std::free(data_); +// +// if (other.heapAllocated_) { +// data_ = other.data_; +// size_ = other.size_; +// capacity_ = other.capacity_; +// heapAllocated_ = true; +// } else { +// std::uninitialized_move(other.data_, other.data_ + other.size_, data_); +// } +// +// other.data_ = reinterpret_cast(other.sbo_); +// other.size_ = 0; +// other.capacity_ = SBO_CAP; +// other.heapAllocated_ = false; +// } +// return *this; +// } +// +// inline void push_back(const T& val) { +// if (size_ == capacity_) reallocate(capacity_ * 2); +// new (data_ + size_) T(val); +// ++size_; +// } +// +// inline void push_back(T&& val) { +// if (size_ == capacity_) reallocate(capacity_ * 2); +// new (data_ + size_) T(std::move(val)); +// ++size_; +// } +// +// inline void pop_back() { +// FV_ASSERT(size_ > 0); +// --size_; +// std::destroy_at(data_ + size_); +// } +// +// inline void clear() { +// std::destroy(data_, data_ + size_); +// size_ = 0; +// } +// +// inline void reserve(size_t newCap) { +// if (newCap > capacity_) reallocate(newCap); +// } +// +// inline void resize(size_t newSize) { +// if (newSize > capacity_) reallocate(newSize); +// if (newSize > size_) { +// std::uninitialized_value_construct(data_ + size_, data_ + newSize); +// } else { +// std::destroy(data_ + newSize, data_ + size_); +// } +// size_ = newSize; +// } +// +// inline T& operator[](size_t i) { +// FV_ASSERT(i < size_); +// return data_[i]; +// } +// +// inline const T& operator[](size_t i) const { +// FV_ASSERT(i < size_); +// return data_[i]; +// } +// +// inline T* data() { return data_; } +// inline const T* data() const { return data_; } +// +// inline size_t size() const { return size_; } +// inline size_t capacity() const { return capacity_; } +// inline bool empty() const { return size_ == 0; } +//}; diff --git a/src/src/core/utils/AssetLoader.cpp b/src/src/core/utils/AssetLoader.cpp deleted file mode 100644 index e69de29..0000000 diff --git a/src/src/core/utils/AssetLoader.h b/src/src/core/utils/AssetLoader.h deleted file mode 100644 index e69de29..0000000 diff --git a/src/src/core/utils/AssetManager.cpp b/src/src/core/utils/AssetManager.cpp new file mode 100644 index 0000000..dd67072 --- /dev/null +++ b/src/src/core/utils/AssetManager.cpp @@ -0,0 +1,243 @@ +#include "AssetManager.h" +#include "utils.h" +#include "../../Renderer.h" +#define STB_IMAGE_IMPLEMENTATION +#include + +#include +#include +#include +#include // for std::hash + +std::unordered_map AssetManager::s_Assets; + +std::mutex AssetManager::s_Mutex; +uint64_t AssetManager::s_NextUAID = 1; + +inline static std::unordered_map s_PathToUAID; + +inline std::string GetFileExtension(const std::string &path) +{ + size_t dot = path.find_last_of('.'); + if (dot == std::string::npos) + return ""; + return path.substr(dot + 1); +} + +inline GLuint CreateOpenGLTexture(unsigned char *data, int width, int height) +{ + GLuint tex; + glGenTextures(1, &tex); + glBindTexture(GL_TEXTURE_2D, tex); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, data); + glBindTexture(GL_TEXTURE_2D, 0); + return tex; +} + +void AssetManager::Init() {} + +uint64_t AssetManager::GenerateUAID() +{ + std::lock_guard lock(s_Mutex); + + static std::random_device rd; + static std::mt19937 gen(rd()); + static std::uniform_int_distribution dist(0, 9); + + std::string digits; + digits.reserve(32); + for (int i = 0; i < 32; ++i) + digits += static_cast('0' + dist(gen)); + + return std::hash{}(digits); +} + +void AssetManager::LoadAssetAsync(const std::string &path, AssetType type) +{ + uint64_t uaid = GenerateUAID(); + + AssetInfo info; + info.uaid = uaid; + info.path = path; + info.filename = GetFilenameFromPath(path); + info.filetype = GetFileExtension(path); + info.type = type; + + { + std::lock_guard lock(s_Mutex); + s_Assets[uaid] = info; + } + + if (type == AssetType::Image) + { + Logger::LogVerbose("[AssetManager] Loading image: %s (UAID: %llu)", path.c_str(), uaid); + LoadImageInternal(path, uaid); + } + else + { + Logger::LogWarning("Unknown Asset Type: '%d'", type); + } +} + +void AssetManager::LoadImageInternal(const std::string &path, uint64_t uaid) +{ + { + std::lock_guard lock(s_Mutex); + auto it = s_PathToUAID.find(path); + if (it != s_PathToUAID.end()) + { + const auto &asset = s_Assets[it->second]; + if (asset.loaded) + { + Logger::LogVerbose("[AssetManager] Skipping already loaded asset: %s (UAID: %llu)", path.c_str(), asset.uaid); + return; + } + } + } + + Logger::LogVerbose("[AssetManager] Begin loading image: %s (UAID: %llu)", path.c_str(), uaid); + + stbi_set_flip_vertically_on_load(false); + + int w, h, channels; + stbi_uc *pixels = stbi_load(path.c_str(), &w, &h, &channels, STBI_rgb_alpha); + if (!pixels) + { + Logger::LogError("[AssetManager] Failed to load image: %s", path.c_str()); + return; + } + + GLuint texID = CreateOpenGLTexture(pixels, w, h); + stbi_image_free(pixels); + + { + std::lock_guard lock(s_Mutex); + + auto &asset = s_Assets[uaid]; + asset.path = path; + asset.filename = GetFilenameFromPath(path); + asset.filetype = GetFileExtension(path); + asset.size = {(float)w, (float)h}; + asset.textureID = texID; + asset.type = AssetType::Image; + asset.loaded = true; + } + + { + std::lock_guard lock(s_Mutex); + s_PathToUAID[path] = uaid; + } + + Logger::LogVerbose("[AssetManager] Finished loading image: %s (%dx%d) (UAID: %llu, Texture ID: %u)", + path.c_str(), w, h, uaid, texID); +} + +const AssetInfo *AssetManager::GetAssetByID(uint64_t uaid) +{ + std::lock_guard lock(s_Mutex); + auto it = s_Assets.find(uaid); + return (it != s_Assets.end()) ? &it->second : nullptr; +} + +const AssetInfo *AssetManager::GetAssetByPath(const std::string &path) +{ + std::lock_guard lock(s_Mutex); + for (const auto &[id, asset] : s_Assets) + if (asset.path == path) + return &asset; + return nullptr; +} + +const std::unordered_map &AssetManager::GetAllAssets() +{ + return s_Assets; // Assume read-only external usage +} + +void AssetManager::UnloadAsset(uint64_t uaid) +{ + std::lock_guard lock(s_Mutex); + auto it = s_Assets.find(uaid); + if (it != s_Assets.end()) + { + if (it->second.textureID) + glDeleteTextures(1, &it->second.textureID); + s_Assets.erase(it); + s_PathToUAID.erase(it->second.path); + + } +} + +void AssetManager::ClearAllAssets() +{ + std::lock_guard lock(s_Mutex); + for (auto &[id, asset] : s_Assets) + { + if (asset.textureID) + glDeleteTextures(1, &asset.textureID); + } + s_Assets.clear(); + s_PathToUAID.clear(); + +} + +void AssetManager::Save(YAML::Emitter &out) +{ + std::lock_guard lock(s_Mutex); + out << YAML::Key << "Assets"; + out << YAML::BeginSeq; + + for (const auto &[uaid, asset] : s_Assets) + { + out << YAML::BeginMap; + out << YAML::Key << "uaid" << YAML::Value << asset.uaid; + out << YAML::Key << "path" << YAML::Value << asset.path; + out << YAML::Key << "filename" << YAML::Value << asset.filename; + out << YAML::Key << "filetype" << YAML::Value << asset.filetype; + out << YAML::Key << "type" << YAML::Value << static_cast(asset.type); + out << YAML::Key << "size" << YAML::Value << YAML::Flow << YAML::BeginSeq << asset.size.x << asset.size.y << YAML::EndSeq; + out << YAML::EndMap; + } + + out << YAML::EndSeq; +} + +void AssetManager::Load(const YAML::Node &node) +{ + if (!node) + return; + + for (const auto &item : node) + { + AssetInfo asset; + asset.uaid = item["uaid"].as(); + asset.path = item["path"].as(); + asset.filename = item["filename"].as(); + asset.filetype = item["filetype"].as(); + asset.type = static_cast(item["type"].as()); + + const auto &size = item["size"]; + asset.size = {size[0].as(), size[1].as()}; + asset.loaded = false; + + { + std::lock_guard lock(s_Mutex); + s_Assets[asset.uaid] = asset; + if (asset.uaid >= s_NextUAID) + s_NextUAID = asset.uaid + 1; + } + + if (asset.type == AssetType::Image) + { + Logger::LogVerbose("[AssetManager] Reloading from file: %s (UAID: %llu)", asset.path.c_str(), asset.uaid); + LoadImageInternal(asset.path, asset.uaid); + } + else + { + Logger::LogWarning("Unknown Asset Type: '%d'", asset.type); + } + } +} diff --git a/src/src/core/utils/AssetManager.h b/src/src/core/utils/AssetManager.h new file mode 100644 index 0000000..4226b5b --- /dev/null +++ b/src/src/core/utils/AssetManager.h @@ -0,0 +1,50 @@ +#pragma once +#include +#include +#include +#include +#include +#include +#include "../types/vec2.h" +#include + + +enum class AssetType { Image, Audio }; + +struct AssetInfo +{ + uint64_t uaid; + std::string path; + std::string filename; + std::string filetype; + AssetType type; + core::types::Vec2 size; + + bool loaded = false; + GLuint textureID = 0; +}; + +class AssetManager +{ +public: + static void Init(); + static void LoadAssetAsync(const std::string& path, AssetType type); + static const AssetInfo* GetAssetByID(uint64_t uaid); + static const AssetInfo* GetAssetByPath(const std::string& path); + static const std::unordered_map& GetAllAssets(); + + static void UnloadAsset(uint64_t uaid); + static void ClearAllAssets(); + + static void Save(YAML::Emitter& out); + static void Load(const YAML::Node& node); + + +private: + static std::unordered_map s_Assets; + static std::mutex s_Mutex; + static uint64_t s_NextUAID; + + static uint64_t GenerateUAID(); + static void LoadImageInternal(const std::string& path, uint64_t uaid); +}; diff --git a/src/src/core/utils/EngineConfig.h b/src/src/core/utils/EngineConfig.h index 51724fd..4884461 100644 --- a/src/src/core/utils/EngineConfig.h +++ b/src/src/core/utils/EngineConfig.h @@ -7,7 +7,7 @@ USER_SETTING(profile_enabled, bool, true) \ USER_SETTING(show_color_correction_window, bool, false) \ USER_SETTING(show_profiler_window, bool, false) \ - USER_SETTING(lighting_enabled, bool, true) \ + USER_SETTING(lighting_enabled, bool, false) \ USER_SETTING(profile_deep, bool, false) \ USER_SETTING(show_asset_window, bool, false) \ USER_SETTING(profile_gpu, bool, false) diff --git a/src/src/core/utils/Texture.cpp b/src/src/core/utils/Texture.cpp index 6e77442..75b1e91 100644 --- a/src/src/core/utils/Texture.cpp +++ b/src/src/core/utils/Texture.cpp @@ -1,19 +1,41 @@ #include "Texture.h" -#include -#include -#include -#include "utils.h" - +#include "AssetManager.h" +#include "Logging.h" Texture::Texture(const std::string &path) { - id = LoadTextureIfNeeded(path); + if (!path.empty()) + { + AssetManager::LoadAssetAsync(path, AssetType::Image); + const auto *asset = AssetManager::GetAssetByPath(path); + if (asset && asset->loaded) + { + id = asset->textureID; + size = asset->size; + } + else + { + Logger::LogError("[Texture] Failed to get asset for path: %s", path.c_str()); + } + } } -Texture::~Texture() +Texture::Texture(uint64_t uaid) { + const auto *asset = AssetManager::GetAssetByID(uaid); + if (asset && asset->loaded) + { + id = asset->textureID; + size = asset->size; + } + else + { + Logger::LogError("[Texture] Failed to get asset for UAID: %llu", uaid); + } } +Texture::~Texture() {} + unsigned int Texture::GetID() const { return id; diff --git a/src/src/core/utils/Texture.h b/src/src/core/utils/Texture.h index 7917883..d4af952 100644 --- a/src/src/core/utils/Texture.h +++ b/src/src/core/utils/Texture.h @@ -1,13 +1,26 @@ #pragma once #include +#include "../types/all.h" + + +enum class RenderType { + Unlit, + Lit +}; class Texture { public: Texture(const std::string& path); + Texture(uint64_t uaid); // New constructor using UAID ~Texture(); unsigned int GetID() const; + void SetSize(core::types::Vec2 newSize) {size = newSize;}; + core::types::Vec2 GetSize() {return size;}; + + private: unsigned int id = 0; + core::types::Vec2 size; }; diff --git a/src/src/core/utils/TextureAtlas.h b/src/src/core/utils/TextureAtlas.h index df7f578..147c2a9 100644 --- a/src/src/core/utils/TextureAtlas.h +++ b/src/src/core/utils/TextureAtlas.h @@ -6,36 +6,62 @@ struct TextureAtlas { std::shared_ptr texture; - int columns = 1; - int rows = 1; + int frameWidth = 1; + int frameHeight = 1; TextureAtlas() = default; - TextureAtlas(std::shared_ptr tex, int cols, int rows) - : texture(std::move(tex)), columns(cols), rows(rows) {} - inline core::types::Vec2 GetFrameUV(int index) const + TextureAtlas(std::shared_ptr tex, int texelW, int texelH) + : texture(std::move(tex)) { - if (columns <= 0 || rows <= 0) - { + SetTexelSize(texelW, texelH); + } + + void SetTexelSize(int texelWidth, int texelHeight) + { + frameWidth = texelWidth; + frameHeight = texelHeight; + } + + core::types::Vec2 GetFrameUV(int index) const + { + if (!texture || frameWidth <= 0 || frameHeight <= 0) return core::types::Vec2(0.0f); - } - int x = index % columns; - int y = index / columns; + int texWidth = texture->GetSize().x; + int texHeight = texture->GetSize().y; - float u = static_cast(x) / static_cast(columns); - float v = static_cast(y) / static_cast(rows); + int cols = texWidth / frameWidth; + int x = index % cols; + int y = index / cols; + + float u = (float)(x * frameWidth) / (float)texWidth; + float v = 1.0f - (float)((y + 1) * frameHeight) / (float)texHeight; // flip y return core::types::Vec2(u, v); } core::types::Vec2 GetFrameSizeUV() const { - return core::types::Vec2(1.0f / float(columns), 1.0f / float(rows)); + if (!texture || frameWidth <= 0 || frameHeight <= 0) + return core::types::Vec2(0.0f); + + return core::types::Vec2( + static_cast(frameWidth) / texture->GetSize().x, + static_cast(frameHeight) / texture->GetSize().y + ); } int GetTotalFrames() const { - return columns * rows; + if (!texture || frameWidth <= 0 || frameHeight <= 0) + return 0; + + int texWidth = texture->GetSize().x; + int texHeight = texture->GetSize().y; + int cols = texWidth / frameWidth; + int rows = texHeight / frameHeight; + + return cols * rows; } }; diff --git a/src/src/core/utils/utils.cpp b/src/src/core/utils/utils.cpp index cc3f99a..82c6be6 100644 --- a/src/src/core/utils/utils.cpp +++ b/src/src/core/utils/utils.cpp @@ -12,6 +12,44 @@ std::unordered_map engineTextureCache; + +ImageCacheEntry LoadImageCache(const std::string& path) +{ + auto [it, inserted] = textureCache.try_emplace(path, ImageCacheEntry{}); + + if (!inserted) + { + return it->second; + } + + int w, h, channels; + stbi_set_flip_vertically_on_load(false); + unsigned char* data = stbi_load(path.c_str(), &w, &h, &channels, 4); + if (!data) + { + Logger::LogError("Failed to load image: '%s'", path.c_str()); + return {}; + } + + GLuint id; + glGenTextures(1, &id); + glBindTexture(GL_TEXTURE_2D, id); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, data); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + stbi_image_free(data); + + glm::vec2 imageSize(w, h); + ImageCacheEntry entry{ id, imageSize }; + it->second = entry; + + Logger::LogVerbose("Loaded Image: (%d, %d) '%s'",w,h, path.c_str()); + Logger::LogWarning("Loaded Image Via Depricated Function: '%s'", path.c_str()); + return entry; +} + + + GLuint LoadTextureIfNeeded(const std::string &path) { auto [it, inserted] = textureCache.try_emplace(path, ImageCacheEntry{}); @@ -39,7 +77,8 @@ GLuint LoadTextureIfNeeded(const std::string &path) it->second = { id, imageSize }; - Logger::LogVerbose("Loaded Image: '%s'", path.c_str()); + Logger::LogVerbose("Loaded Image: (%d, %d) '%s'",w, h, path.c_str()); + return id; } diff --git a/src/src/core/utils/utils.h b/src/src/core/utils/utils.h index aedcb5e..fc279ac 100644 --- a/src/src/core/utils/utils.h +++ b/src/src/core/utils/utils.h @@ -11,6 +11,8 @@ #include "FileDialog.h" #include "EngineConfig.h" +#include "AssetManager.h" + struct ImageCacheEntry { unsigned int textureID; glm::vec2 size; @@ -26,6 +28,8 @@ std::string GetFilenameFromPath(const std::string& path); GLuint LoadTextureIfNeeded(const std::string& path); +ImageCacheEntry LoadImageCache(const std::string& path); + GLuint EngineLoadTextureIfNeeded(const std::string &path); diff --git a/src/src/editor/windows/AssetBrowser.cpp b/src/src/editor/windows/AssetBrowser.cpp index f888791..3861e71 100644 --- a/src/src/editor/windows/AssetBrowser.cpp +++ b/src/src/editor/windows/AssetBrowser.cpp @@ -2,11 +2,10 @@ #include #include "../../core/utils/EngineConfig.h" #include "../../core/utils/utils.h" +#include "../../core/utils/AssetManager.h" #include "../../Renderer.h" #include "../../core/utils/Logging.h" -extern std::unordered_map textureCache; - static std::string assetSearchQuery; void ShowAssetBrowser() @@ -23,13 +22,10 @@ void ShowAssetBrowser() std::string path = OpenFileDialog(FileDialogType::Images); if (!path.empty()) { - LoadTextureIfNeeded(path); + AssetManager::LoadAssetAsync(path, AssetType::Image); } } - - - ImGui::Separator(); char buffer[256] = {}; strncpy(buffer, assetSearchQuery.c_str(), sizeof(buffer) - 1); @@ -40,7 +36,6 @@ void ShowAssetBrowser() } ImGui::Separator(); - ImGui::BeginChild("##AssetScroll", ImVec2(0, 0), true); const float padding = 8.0f; @@ -55,46 +50,51 @@ void ShowAssetBrowser() ImGui::Columns(columns, nullptr, false); int idx = 0; - for (auto it = textureCache.begin(); it != textureCache.end();) + for (const auto& [uaid, asset] : AssetManager::GetAllAssets()) { - const std::string &path = it->first; - auto &entry = it->second; + if (asset.type != AssetType::Image || !asset.loaded) + continue; if (!assetSearchQuery.empty() && - path.find(assetSearchQuery) == std::string::npos) + asset.filename.find(assetSearchQuery) == std::string::npos && + asset.path.find(assetSearchQuery) == std::string::npos) { - ++it; continue; } ImGui::PushID(idx++); - std::string displayName = GetFilenameFromPath(path); + std::string displayName = GetFilenameFromPath(asset.path); - if (ImGui::ImageButton("##Image", - (ImTextureID)(intptr_t)entry.textureID, - ImVec2(thumbnailSize, thumbnailSize), - ImVec2(0, 0), ImVec2(1, 1))) + ImGui::Image((ImTextureID)(intptr_t)asset.textureID, + ImVec2(thumbnailSize, thumbnailSize)); + + if (ImGui::BeginDragDropSource(ImGuiDragDropFlags_SourceAllowNullID)) { - // Optional: preview or inspect + ImGui::SetDragDropPayload("ASSET_TEXTURE", &uaid, sizeof(uint64_t)); + + ImGui::Image((ImTextureID)(intptr_t)asset.textureID, + ImVec2(thumbnailSize * 2, thumbnailSize * 2)); + ImGui::Text("%s", displayName.c_str()); + + ImGui::EndDragDropSource(); } - // Tooltip if (ImGui::IsItemHovered()) { ImGui::BeginTooltip(); - ImGui::Text("Path: %s", path.c_str()); - ImGui::Text("Texture ID: %u", entry.textureID); - ImGui::Text("Size: %dx%d", entry.size.x, entry.size.y); + ImGui::Text("Path: %s", asset.path.c_str()); + ImGui::Text("UAID: %llu", asset.uaid); + ImGui::Text("Texture ID: %u", asset.textureID); + ImGui::Text("Size: (%.0f, %.0f)", asset.size.x, asset.size.y); ImGui::EndTooltip(); } - // Right-click menu if (ImGui::BeginPopupContextItem("AssetContext")) { if (ImGui::MenuItem("Unload")) { - Logger::LogInfo("[AssetBrowser] Unloaded: %s", path.c_str()); - it = textureCache.erase(it); + Logger::LogInfo("[AssetBrowser] Unloaded: %s", asset.path.c_str()); + AssetManager::UnloadAsset(uaid); ImGui::EndPopup(); ImGui::PopID(); continue; @@ -102,28 +102,20 @@ void ShowAssetBrowser() if (ImGui::MenuItem("Copy Path")) { - ImGui::SetClipboardText(path.c_str()); + ImGui::SetClipboardText(asset.path.c_str()); + } + + if (ImGui::MenuItem("Copy UAID")) + { + ImGui::SetClipboardText(std::to_string(asset.uaid).c_str()); } ImGui::EndPopup(); } - if (ImGui::BeginDragDropSource()) - { - ImGui::SetDragDropPayload("ASSET_TEXTURE", - path.c_str(), - path.size() + 1); - ImGui::Image((ImTextureID)(intptr_t)entry.textureID, - ImVec2(thumbnailSize * 2, thumbnailSize * 2)); - ImGui::Text("%s", displayName.c_str()); - ImGui::EndDragDropSource(); - } - ImGui::TextWrapped("%s", displayName.c_str()); ImGui::NextColumn(); ImGui::PopID(); - - ++it; } ImGui::Columns(1); diff --git a/src/src/editor/windows/Inspector.cpp b/src/src/editor/windows/Inspector.cpp index 14d4cbd..49f6a84 100644 --- a/src/src/editor/windows/Inspector.cpp +++ b/src/src/editor/windows/Inspector.cpp @@ -119,20 +119,23 @@ void DrawInspectorUI(std::shared_ptr selected) const char *renderTypes[] = {"Unlit", "Lit"}; int currentTypeIndex = static_cast(sprite->GetRenderType()); if (ImGui::Combo("Render Type", ¤tTypeIndex, renderTypes, IM_ARRAYSIZE(renderTypes))) - sprite->SetRenderType(static_cast(currentTypeIndex)); + sprite->SetRenderType(static_cast(currentTypeIndex)); ImGui::SeparatorText("Texture"); - { - std::string texFile = GetFilenameFromPath(sprite->GetTexturePath()); + const AssetInfo *asset = AssetManager::GetAssetByID(sprite->GetTextureUAID()); + std::string texFile = asset ? GetFilenameFromPath(asset->path) : "(None)"; + ImGui::Text("%s", texFile.c_str()); - ImGui::Text(texFile.c_str()); if (ImGui::BeginDragDropTarget()) { if (const ImGuiPayload *payload = ImGui::AcceptDragDropPayload("ASSET_TEXTURE")) { - const char *dropped = (const char *)payload->Data; - sprite->SetTexture(dropped); + if (payload->DataSize == sizeof(uint64_t)) + { + uint64_t uaid = *reinterpret_cast(payload->Data); + sprite->SetTexture(uaid); + } } ImGui::EndDragDropTarget(); } @@ -141,34 +144,39 @@ void DrawInspectorUI(std::shared_ptr selected) { auto path = OpenFileDialog(FileDialogType::Images); if (!path.empty()) - sprite->SetTexture(path); + sprite->SetTexture(path); // Auto-registers and sets UAID } } + ImGui::SeparatorText("Normal Map"); { - std::string normFile = GetFilenameFromPath(sprite->GetNormalMapPath()); + const AssetInfo *asset = AssetManager::GetAssetByID(sprite->GetNormalMapUAID()); + std::string normFile = asset ? GetFilenameFromPath(asset->path) : "(None)"; + ImGui::Text("%s", normFile.c_str()); - ImGui::Text(normFile.c_str()); if (ImGui::BeginDragDropTarget()) { if (const ImGuiPayload *payload = ImGui::AcceptDragDropPayload("ASSET_TEXTURE")) { - const char *dropped = (const char *)payload->Data; - sprite->SetNormalMap(dropped); + if (payload->DataSize == sizeof(uint64_t)) + { + uint64_t uaid = *reinterpret_cast(payload->Data); + sprite->SetNormalMap(uaid); + } } ImGui::EndDragDropTarget(); } + if (ImGui::SmallButton("Load##SpriteNorm")) { auto path = OpenFileDialog(FileDialogType::Images); if (!path.empty()) - sprite->SetNormalMap(path); + sprite->SetNormalMap(path); // Auto-registers and sets UAID } } ImGui::SeparatorText("Info"); - // — Size Display & Remove — glm::vec2 size = sprite->GetSize(); ImGui::Text("Size: %.0f × %.0f", size.x, size.y); @@ -252,51 +260,61 @@ void DrawInspectorUI(std::shared_ptr selected) if (ImGui::Button("Remove ScriptComponent")) selected->RemoveComponent(); } + if (auto anim = selected->GetComponent()) { ImGui::SeparatorText("Animation Component"); - static int columns = anim->GetAtlas()->columns; - static int rows = anim->GetAtlas()->rows; + static int frameWidth = anim->GetAtlas()->frameWidth; + static int frameHeight = anim->GetAtlas()->frameHeight; static float frameDuration = anim->GetFrameDuration(); static int frameIndex = anim->GetCurrentFrame(); + static int startFrame = 0; + static int endFrame = 0; - // — Texture Preview & Selector — ImGui::SeparatorText("Texture Atlas"); { - std::string texFile = GetFilenameFromPath(anim->GetTexturePath()); - ImGui::Text(texFile.c_str()); - + std::string texFile = "(None)"; + if (const auto* asset = AssetManager::GetAssetByID(anim->GetTextureUAID())) + texFile = GetFilenameFromPath(asset->path); + + ImGui::Text("%s", texFile.c_str()); + if (ImGui::BeginDragDropTarget()) { - if (const ImGuiPayload *payload = ImGui::AcceptDragDropPayload("ASSET_TEXTURE")) + if (const ImGuiPayload* payload = ImGui::AcceptDragDropPayload("ASSET_TEXTURE")) { - const char *dropped = (const char *)payload->Data; - anim->SetTextureAtlas(dropped, columns, rows, frameDuration); + uint64_t droppedUAID = *(const uint64_t*)payload->Data; + anim->SetTextureAtlas(droppedUAID, frameWidth, frameHeight, frameDuration, startFrame, endFrame); } ImGui::EndDragDropTarget(); } - + if (ImGui::SmallButton("Load##AnimTex")) { - auto path = OpenFileDialog(FileDialogType::Images); - if (!path.empty()) - anim->SetTextureAtlas(path, columns, rows, frameDuration); + std::string path = OpenFileDialog(FileDialogType::Images); + if (const auto *asset = AssetManager::GetAssetByPath(path)) + anim->SetTextureAtlas(asset->uaid, frameWidth, frameHeight, frameDuration, startFrame, endFrame); + } } + - // — Grid settings — - ImGui::InputInt("Columns", &columns); - ImGui::InputInt("Rows", &rows); + ImGui::InputInt("Texel Width", &frameWidth); + ImGui::InputInt("Texel Height", &frameHeight); ImGui::InputFloat("Frame Duration", &frameDuration, 0.01f, 0.1f, "%.3f"); - if (ImGui::Button("Apply Grid")) + ImGui::InputInt("Start Frame", &startFrame); + ImGui::InputInt("End Frame", &endFrame); + + if (ImGui::Button("Apply")) { - anim->SetTextureAtlas(anim->GetTexturePath(), columns, rows, frameDuration); + if (const auto *asset = AssetManager::GetAssetByID(anim->GetTextureUAID())) + anim->SetTextureAtlas(asset->uaid, frameWidth, frameHeight, frameDuration, startFrame, endFrame); + } - // — Playback Controls — ImGui::SeparatorText("Playback"); bool isPlaying = anim->IsPlaying(); @@ -318,7 +336,7 @@ void DrawInspectorUI(std::shared_ptr selected) } // Frame scrubber - int maxFrame = columns * rows - 1; + int maxFrame = anim->GetAtlas()->GetTotalFrames() - 1; frameIndex = anim->GetCurrentFrame(); if (ImGui::SliderInt("Current Frame", &frameIndex, 0, maxFrame)) { @@ -331,14 +349,13 @@ void DrawInspectorUI(std::shared_ptr selected) ImGui::SeparatorText("Atlas Viewer"); const float previewSize = 128.0f; - ImVec2 uv0, uv1; - core::types::Vec2 uvMin = anim->GetAtlas()->GetFrameUV(frameIndex); core::types::Vec2 uvSize = anim->GetAtlas()->GetFrameSizeUV(); - uv0 = ImVec2(uvMin.x, uvMin.y); - uv1 = ImVec2(uvMin.x + uvSize.x, uvMin.y + uvSize.y); - ImGui::Image((ImTextureID)(intptr_t)anim->GetAtlas()->texture->GetID(), ImVec2(previewSize, previewSize), uv0, uv1); + ImVec2 uv0 = ImVec2(uvMin.x, uvMin.y + uvSize.y); + ImVec2 uv1 = ImVec2(uvMin.x + uvSize.x, uvMin.y); + + ImGui::Image((ImTextureID)(intptr_t)anim->GetAtlas()->texture->GetID(), ImVec2(previewSize, previewSize), uv1, uv0); } ImGui::Separator(); @@ -367,6 +384,10 @@ void DrawInspectorUI(std::shared_ptr selected) ImGui::ColorEdit4("Start Color", &settings.startColor.r); ImGui::ColorEdit4("End Color", &settings.endColor.r); + bool isRound = settings.roundness > 0.5f; + if (ImGui::Checkbox("Circle", &isRound)) + settings.roundness = isRound ? 1.0f : 0.0f; + ImGui::Checkbox("Loop", &settings.loop); ImGui::Checkbox("Burst", &settings.burst);