Added Actual Asset manager

This commit is contained in:
OusmBlueNinja 2025-04-22 19:26:54 -05:00
parent 421cb639b9
commit c4786629da
35 changed files with 1354 additions and 730 deletions

View File

@ -10,97 +10,93 @@ Collapsed=1
[Window][WindowOverViewport_11111111] [Window][WindowOverViewport_11111111]
Pos=0,19 Pos=0,19
Size=1280,701 Size=1920,1158
Collapsed=0 Collapsed=0
[Window][Inspector] [Window][Inspector]
Pos=0,421 Pos=1578,19
Size=342,299 Size=342,1158
Collapsed=0 Collapsed=0
DockId=0x0000000A,0 DockId=0x00000006,0
[Window][Scene Tree] [Window][Scene Tree]
Pos=0,19 Pos=0,19
Size=342,400 Size=342,575
Collapsed=0 Collapsed=0
DockId=0x00000009,0 DockId=0x00000003,0
[Window][Viewport] [Window][Viewport]
Pos=344,19 Pos=344,19
Size=936,139 Size=1232,847
Collapsed=0 Collapsed=0
DockId=0x0000000B,0 DockId=0x00000007,0
[Window][##MainMenuBar] [Window][##MainMenuBar]
Size=1920,19 Size=1920,19
Collapsed=0 Collapsed=0
[Window][Performance Info] [Window][Performance Info]
Pos=1083,410 Pos=0,19
Size=197,310 Size=342,575
Collapsed=0 Collapsed=0
DockId=0x00000006,0 DockId=0x00000003,1
[Window][Console] [Window][Console]
Pos=344,410 Pos=344,868
Size=286,310 Size=1232,309
Collapsed=0 Collapsed=0
DockId=0x0000000D,0 DockId=0x00000008,0
[Window][Tilemap Editor] [Window][Tilemap Editor]
Pos=265,19 Pos=265,19
Size=1263,674 Size=1263,674
Collapsed=0 Collapsed=0
DockId=0x0000000B,1 DockId=0x00000007,1
[Window][Profiler] [Window][Profiler]
Pos=344,160 Pos=344,868
Size=936,248 Size=1232,309
Collapsed=0 Collapsed=0
DockId=0x0000000C,0 DockId=0x00000008,1
[Window][Profiler Timeline] [Window][Profiler Timeline]
Pos=265,69 Pos=265,69
Size=623,651 Size=623,651
Collapsed=0 Collapsed=0
DockId=0x00000005,1 DockId=0x00000008,1
[Window][Profiler (Unity Style)] [Window][Profiler (Unity Style)]
Pos=265,430 Pos=265,430
Size=623,290 Size=623,290
Collapsed=0 Collapsed=0
DockId=0x00000005,1 DockId=0x00000008,1
[Window][Profiler Timeline View] [Window][Profiler Timeline View]
Pos=265,526 Pos=265,526
Size=1263,651 Size=1263,651
Collapsed=0 Collapsed=0
DockId=0x00000005,1 DockId=0x00000008,1
[Window][Color Correction] [Window][Color Correction]
Pos=1083,410 Pos=1588,867
Size=197,310 Size=332,310
Collapsed=0 Collapsed=0
DockId=0x00000006,1 DockId=0x00000008,1
[Window][Asset Browser] [Window][Asset Browser]
Pos=632,410 Pos=0,596
Size=449,310 Size=342,581
Collapsed=0 Collapsed=0
DockId=0x0000000E,0 DockId=0x00000004,0
[Docking][Data] [Docking][Data]
DockSpace ID=0x11111111 Window=0x1BBC0F80 Pos=0,19 Size=1280,701 Split=X DockSpace ID=0x11111111 Window=0x1BBC0F80 Pos=0,19 Size=1920,1158 Split=X
DockNode ID=0x00000001 Parent=0x11111111 SizeRef=342,701 Split=Y Selected=0x12EF0F59 DockNode ID=0x00000005 Parent=0x11111111 SizeRef=1576,1158 Split=X
DockNode ID=0x00000009 Parent=0x00000001 SizeRef=385,662 Selected=0x12EF0F59 DockNode ID=0x00000001 Parent=0x00000005 SizeRef=342,701 Split=Y Selected=0x12EF0F59
DockNode ID=0x0000000A Parent=0x00000001 SizeRef=385,494 HiddenTabBar=1 Selected=0x36DC96AB DockNode ID=0x00000003 Parent=0x00000001 SizeRef=342,575 Selected=0x12EF0F59
DockNode ID=0x00000002 Parent=0x11111111 SizeRef=1576,701 Split=Y Selected=0xC450F867 DockNode ID=0x00000004 Parent=0x00000001 SizeRef=342,581 HiddenTabBar=1 Selected=0x36AF052B
DockNode ID=0x00000007 Parent=0x00000002 SizeRef=606,846 Split=Y Selected=0xC450F867 DockNode ID=0x00000002 Parent=0x00000005 SizeRef=1576,701 Split=Y Selected=0xC450F867
DockNode ID=0x0000000B Parent=0x00000007 SizeRef=1576,596 CentralNode=1 HiddenTabBar=1 Selected=0xC450F867 DockNode ID=0x00000007 Parent=0x00000002 SizeRef=606,847 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,309 Selected=0x9B5D3198
DockNode ID=0x00000008 Parent=0x00000002 SizeRef=606,310 Split=X Selected=0x9B5D3198 DockNode ID=0x00000006 Parent=0x11111111 SizeRef=342,1158 Selected=0x36DC96AB
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

View File

@ -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\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\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\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\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 [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
[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 [ERROR] Runtime crash
[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 Command 'src\build\app.exe' returned non-zero exit status 3221225477.
[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.

View File

@ -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

View File

@ -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]

View File

@ -1,6 +1,6 @@
engine_version: 0.1.0 engine_version: 0.1.0
scene_name: lighting_test scene_name: lighting_test
scene_hash: 964a6472a140773c791bf1ed2b8e6ea5b20b183e7bb02489110ad41df5d364e2 scene_hash: ee7d7a88a6c1a4eaa0ae27372e3d055df3511e13144a267574ebb7a7842d63d2
format_version: 1 format_version: 1
objects: objects:
- name: Tiles - name: Tiles
@ -21,86 +21,47 @@ objects:
visable: true visable: true
components: components:
- type: SpriteComponent - type: SpriteComponent
texture: C:\Users\spenc\OneDrive\Pictures\textures\bark_willow_02_diff_1k.png texture: 1
normalMap: C:\Users\spenc\OneDrive\Pictures\textures\bark_willow_02_nor_gl_1k.png normalMap: 2
renderType: Lit renderType: Lit
children: [] children: []
- name: Planks - name: Planks
uid: 13d8988343354e3c8a1f51c03ed40cda uid: 13d8988343354e3c8a1f51c03ed40cda
id: 5 id: 5
position: [1024, 0] position: [2048, 0]
rotation: 0 rotation: 0
layer: 0 layer: 0
visable: true visable: true
components: components:
- type: SpriteComponent - type: SpriteComponent
texture: C:\Users\spenc\OneDrive\Pictures\textures\wood_floor_worn_diff_1k.png texture: 3
normalMap: C:\Users\spenc\OneDrive\Pictures\textures\wood_floor_worn_nor_gl_1k.png normalMap: 4
renderType: Lit renderType: Lit
children: [] children: []
- name: Rocks - name: Rocks
uid: cff28abe7e3b455ab9b756acc84cd2d7 uid: cff28abe7e3b455ab9b756acc84cd2d7
id: 6 id: 6
position: [0, 1024] position: [0, 2048]
rotation: 0 rotation: 0
layer: 0 layer: 0
visable: true visable: true
components: components:
- type: SpriteComponent - type: SpriteComponent
texture: C:\Users\spenc\OneDrive\Pictures\textures\ganges_river_pebbles_diff_1k.png texture: 6
normalMap: C:\Users\spenc\OneDrive\Pictures\textures\ganges_river_pebbles_nor_gl_1k.png normalMap: 5
renderType: Lit renderType: Lit
children: [] children: []
- name: Metal - name: Metal
uid: 98967eb30e5b429b992766d8062b7c17 uid: 98967eb30e5b429b992766d8062b7c17
id: 7 id: 7
position: [1024, 1024] position: [2048, 2048]
rotation: 0 rotation: 0
layer: 0 layer: 0
visable: true visable: true
components: components:
- type: SpriteComponent - type: SpriteComponent
texture: C:\Users\spenc\OneDrive\Pictures\textures\metal_plate_diff_1k.png texture: 7
normalMap: C:\Users\spenc\OneDrive\Pictures\textures\metal_plate_nor_gl_1k.png normalMap: 8
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
renderType: Lit renderType: Lit
children: [] children: []
- name: Lights - name: Lights
@ -115,7 +76,7 @@ objects:
- name: Red - name: Red
uid: 6afde2dd47aa4557b6afb1a607c99dc8 uid: 6afde2dd47aa4557b6afb1a607c99dc8
id: 13 id: 13
position: [878.398376, 545.669373] position: [574.239258, 805.561768]
rotation: 0 rotation: 0
layer: 2 layer: 2
visable: true visable: true
@ -133,7 +94,7 @@ objects:
- name: Green - name: Green
uid: 0f950d76d24b4dc18f54cab2c3aaaf9a uid: 0f950d76d24b4dc18f54cab2c3aaaf9a
id: 14 id: 14
position: [1511.04724, 1137.07068] position: [1438.05347, 743.714905]
rotation: 0 rotation: 0
layer: 2 layer: 2
visable: true visable: true
@ -151,7 +112,7 @@ objects:
- name: Blue - name: Blue
uid: 09f722f51c7c4b0f98de3a0a16d127c4 uid: 09f722f51c7c4b0f98de3a0a16d127c4
id: 15 id: 15
position: [682.554321, 1389.26001] position: [1059.70728, 1522.72339]
rotation: 0 rotation: 0
layer: 2 layer: 2
visable: true visable: true
@ -232,6 +193,7 @@ objects:
endColor: [0.792156875, 0, 1, 1] endColor: [0.792156875, 0, 1, 1]
loop: true loop: true
burst: false burst: false
roundness: 1
children: [] children: []
- name: Rain - name: Rain
uid: 19253834f75d4e69a618c45ddb14e8b0 uid: 19253834f75d4e69a618c45ddb14e8b0
@ -256,6 +218,7 @@ objects:
endColor: [0, 0, 1, 0] endColor: [0, 0, 1, 0]
loop: true loop: true
burst: false burst: false
roundness: 1
children: [] children: []
- name: Fire - name: Fire
uid: 995af3d194694309a490504eaee3ae92 uid: 995af3d194694309a490504eaee3ae92
@ -280,11 +243,61 @@ objects:
endColor: [1, 0, 0, 0] endColor: [1, 0, 0, 0]
loop: true loop: true
burst: false burst: false
roundness: 1
children: [] children: []
color_correction: color_correction:
brightness: 2 brightness: 2
saturation: 2 saturation: 2
gamma: 1.05999994 gamma: 1.05999994
bloom: true bloom: true
intensity: 1.40999997 intensity: 1.35000002
threshold: 0.300000012 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]

View File

@ -1,12 +1,12 @@
engine_version: 0.1.0 engine_version: 0.1.0
scene_name: lighting_test_2 scene_name: lighting_test_2
scene_hash: 8d1aa1b7b386c5e68c5ad14aa2db10dad6c1fef078b7cbd009df408784b8f915 scene_hash: fd4d1e65a004b05f9654d657efa90617ff63d3c6c4e624518825d4dae50ef3a3
format_version: 1 format_version: 1
objects: objects:
- name: Tiles - name: Tiles
uid: f5e01f7892874a67b662633650b41dbd uid: f5e01f7892874a67b662633650b41dbd
id: 3 id: 3
position: [0, 0] position: [426, 1088]
rotation: 0 rotation: 0
layer: 0 layer: 0
visable: true visable: true
@ -21,86 +21,47 @@ objects:
visable: true visable: true
components: components:
- type: SpriteComponent - type: SpriteComponent
texture: C:\Users\spenc\OneDrive\Pictures\textures\bark_willow_02_diff_1k.png texture: 1
normalMap: C:\Users\spenc\OneDrive\Pictures\textures\bark_willow_02_nor_gl_1k.png normalMap: 2
renderType: Lit renderType: Lit
children: [] children: []
- name: Planks - name: Planks
uid: 13d8988343354e3c8a1f51c03ed40cda uid: 13d8988343354e3c8a1f51c03ed40cda
id: 5 id: 5
position: [1024, 0] position: [2048, 0]
rotation: 0 rotation: 0
layer: 0 layer: 0
visable: true visable: true
components: components:
- type: SpriteComponent - type: SpriteComponent
texture: C:\Users\spenc\OneDrive\Pictures\textures\wood_floor_worn_diff_1k.png texture: 3
normalMap: C:\Users\spenc\OneDrive\Pictures\textures\wood_floor_worn_nor_gl_1k.png normalMap: 4
renderType: Lit renderType: Lit
children: [] children: []
- name: Rocks - name: Rocks
uid: cff28abe7e3b455ab9b756acc84cd2d7 uid: cff28abe7e3b455ab9b756acc84cd2d7
id: 6 id: 6
position: [0, 1024] position: [0, 2048]
rotation: 0 rotation: 0
layer: 0 layer: 0
visable: true visable: true
components: components:
- type: SpriteComponent - type: SpriteComponent
texture: C:\Users\spenc\OneDrive\Pictures\textures\ganges_river_pebbles_diff_1k.png texture: 6
normalMap: C:\Users\spenc\OneDrive\Pictures\textures\ganges_river_pebbles_nor_gl_1k.png normalMap: 5
renderType: Lit renderType: Lit
children: [] children: []
- name: Metal - name: Metal
uid: 98967eb30e5b429b992766d8062b7c17 uid: 98967eb30e5b429b992766d8062b7c17
id: 7 id: 7
position: [1024, 1024] position: [2048, 2048]
rotation: 0 rotation: 0
layer: 0 layer: 0
visable: true visable: true
components: components:
- type: SpriteComponent - type: SpriteComponent
texture: C:\Users\spenc\OneDrive\Pictures\textures\metal_plate_diff_1k.png texture: 7
normalMap: C:\Users\spenc\OneDrive\Pictures\textures\metal_plate_nor_gl_1k.png normalMap: 8
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
renderType: Lit renderType: Lit
children: [] children: []
- name: Lights - name: Lights
@ -115,7 +76,7 @@ objects:
- name: Red - name: Red
uid: 6afde2dd47aa4557b6afb1a607c99dc8 uid: 6afde2dd47aa4557b6afb1a607c99dc8
id: 13 id: 13
position: [574.239258, 805.561768] position: [1062.8678, 525.513]
rotation: 0 rotation: 0
layer: 2 layer: 2
visable: true visable: true
@ -133,7 +94,7 @@ objects:
- name: Green - name: Green
uid: 0f950d76d24b4dc18f54cab2c3aaaf9a uid: 0f950d76d24b4dc18f54cab2c3aaaf9a
id: 14 id: 14
position: [1438.05347, 743.714905] position: [1436.26843, 1306.90405]
rotation: 0 rotation: 0
layer: 2 layer: 2
visable: true visable: true
@ -151,7 +112,7 @@ objects:
- name: Blue - name: Blue
uid: 09f722f51c7c4b0f98de3a0a16d127c4 uid: 09f722f51c7c4b0f98de3a0a16d127c4
id: 15 id: 15
position: [1059.70728, 1522.72339] position: [572.863647, 1239.58301]
rotation: 0 rotation: 0
layer: 2 layer: 2
visable: true visable: true
@ -232,6 +193,7 @@ objects:
endColor: [0.792156875, 0, 1, 1] endColor: [0.792156875, 0, 1, 1]
loop: true loop: true
burst: false burst: false
roundness: 1
children: [] children: []
- name: Rain - name: Rain
uid: 19253834f75d4e69a618c45ddb14e8b0 uid: 19253834f75d4e69a618c45ddb14e8b0
@ -256,6 +218,7 @@ objects:
endColor: [0, 0, 1, 0] endColor: [0, 0, 1, 0]
loop: true loop: true
burst: false burst: false
roundness: 1
children: [] children: []
- name: Fire - name: Fire
uid: 995af3d194694309a490504eaee3ae92 uid: 995af3d194694309a490504eaee3ae92
@ -280,11 +243,61 @@ objects:
endColor: [1, 0, 0, 0] endColor: [1, 0, 0, 0]
loop: true loop: true
burst: false burst: false
roundness: 1
children: [] children: []
color_correction: color_correction:
brightness: 2 brightness: 2
saturation: 2 saturation: 2
gamma: 1.05999994 gamma: 1.05999994
bloom: true bloom: true
intensity: 1.40999997 intensity: 0.200000003
threshold: 0.300000012 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]

View File

@ -1,6 +1,10 @@
#version 430 core #version 430 core
in vec2 vUV; in vec2 vUV;
uniform vec2 uUVMin;
uniform vec2 uUVMax;
in vec2 vFragScreenPos; in vec2 vFragScreenPos;
out vec4 FragColor; out vec4 FragColor;
@ -18,6 +22,8 @@ uniform int uClusterHeight;
uniform int uClusterCols; uniform int uClusterCols;
uniform int uMaxLightsPerCluster; uniform int uMaxLightsPerCluster;
#define MAX_LIGHTS 512 #define MAX_LIGHTS 512
uniform vec2 uLightPos[MAX_LIGHTS]; uniform vec2 uLightPos[MAX_LIGHTS];
uniform vec3 uLightColor[MAX_LIGHTS]; uniform vec3 uLightColor[MAX_LIGHTS];
@ -30,7 +36,9 @@ layout(std430, binding = 1) readonly buffer ClusterLightBuffer {
void main() 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); vec4 texColor = texture(uTex, rotatedUV);
if (texColor.a < 0.1) if (texColor.a < 0.1)
discard; discard;

View File

@ -1,15 +1,21 @@
#version 330 core #version 330 core
in vec2 vUV; in vec2 vUV;
out vec4 FragColor; out vec4 FragColor;
uniform sampler2D uTex; uniform sampler2D uTex;
uniform vec2 uUVMin;
uniform vec2 uUVMax;
void main() void main()
{ {
// Rotate UV 90 degrees to the right: (x, y) → (y, 1 - x)
vec2 rotatedUV = vec2(vUV.y, 1.0 - vUV.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) if (color.a < 0.01)
discard; discard;

View File

@ -1,4 +1,4 @@
#version 330 core #version 430 core
layout (location = 0) in vec2 aPos; layout (location = 0) in vec2 aPos;
layout (location = 1) in vec2 aUV; layout (location = 1) in vec2 aUV;

View File

@ -1,11 +1,23 @@
#version 330 core #version 330 core
in vec4 vColor; in vec4 vColor;
in vec2 vUV;
in float vRoundness;
out vec4 FragColor; out vec4 FragColor;
void main() { void main()
// Optional: kill particles with near-zero alpha (optional) {
if (vColor.a < 0.01) 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; discard;
FragColor = vColor; FragColor = vColor;

View File

@ -1,4 +1,4 @@
#version 330 core #version 430 core
layout (location = 0) in vec2 aPos; layout (location = 0) in vec2 aPos;
@ -6,12 +6,17 @@ layout (location = 1) in vec2 iPos;
layout (location = 2) in vec2 iSize; layout (location = 2) in vec2 iSize;
layout (location = 3) in float iRot; layout (location = 3) in float iRot;
layout (location = 4) in vec4 iColor; layout (location = 4) in vec4 iColor;
layout (location = 5) in float iRoundness; // 0 to 1 rounded
uniform vec2 uScreen; uniform vec2 uScreen;
out vec4 vColor; out vec4 vColor;
out float vRoundness;
out vec2 vUV;
void main() {
void main()
{
float cosR = cos(iRot); float cosR = cos(iRot);
float sinR = sin(iRot); float sinR = sin(iRot);
@ -24,5 +29,9 @@ void main() {
vec2 finalPos = iPos + rotated; vec2 finalPos = iPos + rotated;
gl_Position = vec4((finalPos / uScreen * 2.0 - 1.0) * vec2(1, -1), 0.0, 1.0); 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; vColor = iColor;
vRoundness = iRoundness;
} }

View File

@ -1,71 +1,117 @@
#include "AnimationComponent.h" #include "AnimationComponent.h"
AnimationComponent::AnimationComponent(Object* owner) AnimationComponent::AnimationComponent(Object *owner)
: Component(owner) {} : Component(owner) {}
void AnimationComponent::SetTextureAtlas(const std::string& path, int cols, int rows, float duration) { void AnimationComponent::SetTextureAtlasPath(const std::string &path, int texelWidth, int texelHeight, float duration, int start, int end)
texturePath = path; {
texture = std::make_shared<Texture>(path); AssetManager::LoadAssetAsync(path, AssetType::Image);
atlas = TextureAtlas(texture, cols, rows); const auto *asset = AssetManager::GetAssetByPath(path);
columns = cols; if (asset)
rows = rows; SetTextureAtlas(asset->uaid, texelWidth, texelHeight, duration, start, end);
totalFrames = cols * rows; }
frameDuration = duration;
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<int>(asset->size.x);
int texHeight = static_cast<int>(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<Texture>(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::Play() { playing = true; }
void AnimationComponent::Stop() { playing = false; } void AnimationComponent::Stop() { playing = false; }
void AnimationComponent::SetLooping(bool l) { loop = l; } void AnimationComponent::SetLooping(bool l) { loop = l; }
void AnimationComponent::SetSpeed(float s) { speed = s; } 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) { void AnimationComponent::Update(float dt)
if (!playing || totalFrames <= 1) return; {
if (!playing || totalFrames <= 1)
return;
time += dt * speed; time += dt * speed;
if (time >= frameDuration) { if (time >= frameDuration)
{
time -= frameDuration; time -= frameDuration;
currentFrame++; currentFrame++;
if (currentFrame >= totalFrames) { if (currentFrame > endFrame)
{
if (loop) if (loop)
currentFrame = 0; currentFrame = startFrame;
else { else
currentFrame = totalFrames - 1; {
currentFrame = endFrame;
playing = false; playing = false;
} }
} }
} }
} }
std::string AnimationComponent::GetName() const { return "AnimationComponent"; }
void AnimationComponent::Save(YAML::Emitter &out) const
std::string AnimationComponent::GetName() const { {
return "AnimationComponent";
}
void AnimationComponent::Save(YAML::Emitter& out) const {
out << YAML::Key << "AnimationComponent"; out << YAML::Key << "AnimationComponent";
out << YAML::BeginMap; out << YAML::BeginMap;
out << YAML::Key << "TexturePath" << YAML::Value << texturePath; out << YAML::Key << "TextureUAID" << YAML::Value << textureUAID;
out << YAML::Key << "Columns" << YAML::Value << columns; out << YAML::Key << "TexelWidth" << YAML::Value << atlas.frameWidth;
out << YAML::Key << "Rows" << YAML::Value << rows; out << YAML::Key << "TexelHeight" << YAML::Value << atlas.frameHeight;
out << YAML::Key << "FrameDuration" << YAML::Value << frameDuration; out << YAML::Key << "FrameDuration" << YAML::Value << frameDuration;
out << YAML::Key << "StartFrame" << YAML::Value << startFrame;
out << YAML::Key << "EndFrame" << YAML::Value << endFrame;
out << YAML::EndMap; out << YAML::EndMap;
} }
void AnimationComponent::Load(const YAML::Node& node) { void AnimationComponent::Load(const YAML::Node &node)
{
if (!node["AnimationComponent"]) if (!node["AnimationComponent"])
return; return;
const auto& data = node["AnimationComponent"]; const auto &data = node["AnimationComponent"];
std::string path = data["TexturePath"].as<std::string>(); uint64_t uaid = data["TextureUAID"].as<uint64_t>();
int cols = data["Columns"].as<int>(); int texelWidth = data["TexelWidth"].as<int>();
int rows = data["Rows"].as<int>(); int texelHeight = data["TexelHeight"].as<int>();
float duration = data["FrameDuration"].as<float>(); float duration = data["FrameDuration"].as<float>();
int start = data["StartFrame"] ? data["StartFrame"].as<int>() : 0;
int end = data["EndFrame"] ? data["EndFrame"].as<int>() : INT_MAX;
SetTextureAtlas(path, cols, rows, duration); SetTextureAtlas(uaid, texelWidth, texelHeight, duration, start, end);
} }

View File

@ -6,13 +6,17 @@
#include <memory> #include <memory>
#include "../core/utils/Texture.h" #include "../core/utils/Texture.h"
#include "../core/utils/TextureAtlas.h" #include "../core/utils/TextureAtlas.h"
#include "../core/utils/AssetManager.h"
#include "../core/utils/Logging.h"
class AnimationComponent : public Component class AnimationComponent : public Component
{ {
public: public:
AnimationComponent(Object *owner); 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 Play();
void Stop(); void Stop();
@ -25,9 +29,11 @@ public:
float GetSpeed() const { return speed; } float GetSpeed() const { return speed; }
TextureAtlas *GetAtlas() { return &atlas; } TextureAtlas *GetAtlas() { return &atlas; }
const TextureAtlas *GetAtlas() const { return &atlas; }
int GetCurrentFrame() const { return currentFrame; } int GetCurrentFrame() const { return currentFrame; }
const std::string &GetTexturePath() const { return texturePath; } uint64_t GetTextureUAID() const { return textureUAID; }
float GetFrameDuration() const { return frameDuration; } float GetFrameDuration() const { return frameDuration; }
void Update(float dt); void Update(float dt);
@ -36,9 +42,11 @@ public:
void Save(YAML::Emitter &out) const override; void Save(YAML::Emitter &out) const override;
void Load(const YAML::Node &node) override; void Load(const YAML::Node &node) override;
private:
std::string texturePath;
RenderType renderType;
private:
std::shared_ptr<Texture> texture; std::shared_ptr<Texture> texture;
TextureAtlas atlas; TextureAtlas atlas;
@ -46,10 +54,15 @@ private:
int rows = 1; int rows = 1;
int totalFrames = 1; int totalFrames = 1;
int startFrame = 0;
int endFrame = 0;
float frameDuration = 0.1f; float frameDuration = 0.1f;
float time = 0.0f; float time = 0.0f;
int currentFrame = 0; int currentFrame = 0;
bool playing = true; bool playing = true;
bool loop = true; bool loop = true;
float speed = 1.0f; float speed = 1.0f;
uint64_t textureUAID = 0;
}; };

View File

@ -1,5 +1,5 @@
#include "ParticleComponent.h" #include "ParticleComponent.h"
#include "../Renderer.h" // Adjust if needed #include "../Renderer.h"
#include <random> #include <random>
#include <algorithm> #include <algorithm>
@ -55,7 +55,6 @@ void ParticleComponent::Update(float dt)
particles.end()); particles.end());
} }
void ParticleComponent::SpawnParticle() void ParticleComponent::SpawnParticle()
{ {
Particle p; Particle p;
@ -73,7 +72,8 @@ void ParticleComponent::SpawnParticle()
particles.push_back(p); particles.push_back(p);
} }
void ParticleComponent::Save(YAML::Emitter& out) const
void ParticleComponent::Save(YAML::Emitter &out) const
{ {
out << YAML::BeginMap; out << YAML::BeginMap;
out << YAML::Key << "type" << YAML::Value << "ParticleComponent"; 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 << "direction" << YAML::Value << YAML::Flow << YAML::BeginSeq << settings.direction.x << settings.direction.y << YAML::EndSeq;
out << YAML::Key << "spread" << YAML::Value << settings.spread; 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; 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 << "loop" << YAML::Value << settings.loop;
out << YAML::Key << "burst" << YAML::Value << settings.burst; out << YAML::Key << "burst" << YAML::Value << settings.burst;
out << YAML::Key << "roundness" << YAML::Value << settings.roundness;
out << YAML::EndMap; out << YAML::EndMap;
} }
void ParticleComponent::Load(const YAML::Node &node)
void ParticleComponent::Load(const YAML::Node& node)
{ {
if (!node || !node.IsMap()) if (!node || !node.IsMap())
return; return;
auto vec2 = [](const YAML::Node& n) auto vec2 = [](const YAML::Node &n)
{ {
return Vec2(n[0].as<float>(), n[1].as<float>()); return Vec2(n[0].as<float>(), n[1].as<float>());
}; };
auto color = [](const YAML::Node& n) auto color = [](const YAML::Node &n)
{ {
return Color(n[0].as<float>(), n[1].as<float>(), n[2].as<float>(), n[3].as<float>()); return Color(n[0].as<float>(), n[1].as<float>(), n[2].as<float>(), n[3].as<float>());
}; };
@ -142,4 +143,6 @@ void ParticleComponent::Load(const YAML::Node& node)
settings.loop = node["loop"].as<bool>(); settings.loop = node["loop"].as<bool>();
if (node["burst"]) if (node["burst"])
settings.burst = node["burst"].as<bool>(); settings.burst = node["burst"].as<bool>();
if (node["roundness"])
settings.roundness = node["roundness"].as<float>();
} }

View File

@ -13,6 +13,22 @@
#include <string> #include <string>
#include <yaml-cpp/yaml.h> #include <yaml-cpp/yaml.h>
enum class ParticleShape
{
Circle,
Square,
// Triangle,
// Line,
// Star,
// Hexagon,
// Diamond,
// Cross,
// Outline
MAX_SHAPE
};
struct Particle struct Particle
{ {
core::types::Vec2 position; core::types::Vec2 position;
@ -39,8 +55,11 @@ struct ParticleEmitterSettings
core::types::Color endColor = {1, 1, 1, 0}; core::types::Color endColor = {1, 1, 1, 0};
bool loop = true; bool loop = true;
bool burst = false; bool burst = false;
float roundness = 1.0f; // 0 = square, 1 = circle
}; };
class ParticleComponent : public Component class ParticleComponent : public Component
{ {
public: public:

View File

@ -1,81 +1,12 @@
#include "SpriteComponent.h" #include "SpriteComponent.h"
#define STB_IMAGE_IMPLEMENTATION #include "../core/utils/AssetManager.h"
#include <stb_image.h>
#include <unordered_map>
#include <GL/glew.h>
#include <iostream>
#include "../core/utils/Logging.h" #include "../core/utils/Logging.h"
#include "../core/utils/utils.h"
#include <GL/glew.h>
SpriteComponent::SpriteComponent(Object *owner) : Component(owner) {} 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() bool SpriteComponent::HasTexture()
{ {
return texture_loaded; return texture_loaded;
@ -83,22 +14,44 @@ bool SpriteComponent::HasTexture()
void SpriteComponent::SetTexture(const std::string &path) void SpriteComponent::SetTexture(const std::string &path)
{ {
if (path.empty()) if (path.empty()) return;
return;
texturePath = path; AssetManager::LoadAssetAsync(path, AssetType::Image);
textureID = LoadTexture(path, true); const auto* asset = AssetManager::GetAssetByPath(path);
if (textureID != 0) if (asset)
{ SetTexture(asset->uaid);
texture_loaded = true;
}
} }
void SpriteComponent::SetNormalMap(const std::string &path) void SpriteComponent::SetNormalMap(const std::string &path)
{ {
if (path.empty()) if (path.empty()) return;
return;
normalMapPath = path; AssetManager::LoadAssetAsync(path, AssetType::Image);
normalMapID = LoadTexture(path, false); 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 unsigned int SpriteComponent::GetTextureID() const
@ -111,62 +64,42 @@ unsigned int SpriteComponent::GetNormalMapID() const
return normalMapID; 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 void SpriteComponent::Save(YAML::Emitter &out) const
{ {
out << YAML::BeginMap; out << YAML::BeginMap;
out << YAML::Key << "type" << YAML::Value << "SpriteComponent"; out << YAML::Key << "type" << YAML::Value << "SpriteComponent";
out << YAML::Key << "texture" << YAML::Value << texturePath; out << YAML::Key << "texture" << YAML::Value << textureUAID;
out << YAML::Key << "normalMap" << YAML::Value << normalMapPath; out << YAML::Key << "normalMap" << YAML::Value << normalMapUAID;
out << YAML::Key << "renderType" << YAML::Value << (renderType == RenderType::Lit ? "Lit" : "Unlit"); out << YAML::Key << "renderType" << YAML::Value << (renderType == RenderType::Lit ? "Lit" : "Unlit");
out << YAML::EndMap; out << YAML::EndMap;
} }
void SpriteComponent::Load(const YAML::Node& node) void SpriteComponent::Load(const YAML::Node& node)
{ {
try { try {
if (!node["texture"]) if (node["texture"])
{ SetTexture(node["texture"].as<uint64_t>());
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<std::string>().empty())
{
SetTexture(node["texture"].as<std::string>());
}
if (!node["normalMap"]) if (node["normalMap"])
{ SetNormalMap(node["normalMap"].as<uint64_t>());
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<std::string>().empty())
{
SetNormalMap(node["normalMap"].as<std::string>());
}
if (node["renderType"] && node["renderType"].IsScalar()) { if (node["renderType"] && node["renderType"].IsScalar()) {
std::string typeStr = node["renderType"].as<std::string>(); std::string typeStr = node["renderType"].as<std::string>();
if (typeStr == "Lit") renderType = RenderType::Lit; if (typeStr == "Lit") renderType = RenderType::Lit;
else if (typeStr == "Unlit") renderType = RenderType::Unlit; else if (typeStr == "Unlit") renderType = RenderType::Unlit;
else 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) { } catch (const YAML::Exception& e) {

View File

@ -3,54 +3,42 @@
#include "Component.h" #include "Component.h"
#include <string> #include <string>
#include <glm/glm.hpp> #include <glm/glm.hpp>
#include "../core/utils/AssetManager.h"
#include "../core/utils/Texture.h"
class SpriteComponent : public Component { class SpriteComponent : public Component {
public: public:
SpriteComponent(Object* owner); SpriteComponent(Object* owner);
enum class RenderType {
Unlit,
Lit
};
void SetTexture(const std::string& path); void SetTexture(const std::string& path);
void SetTexture(uint64_t uaid);
void SetNormalMap(const std::string& path); void SetNormalMap(const std::string& path);
void SetNormalMap(uint64_t uaid);
unsigned int GetTextureID() const; unsigned int GetTextureID() const;
unsigned int GetNormalMapID() const; unsigned int GetNormalMapID() const;
uint64_t GetTextureUAID() const;
std::string GetTexturePath() const; uint64_t GetNormalMapUAID() const;
std::string GetNormalMapPath() const;
bool HasTexture(); bool HasTexture();
RenderType GetRenderType() const { return renderType; } RenderType GetRenderType() const { return renderType; }
void SetRenderType(RenderType type) { renderType = type; } void SetRenderType(RenderType type) { renderType = type; }
virtual glm::vec2 GetSize() const { return size; } virtual glm::vec2 GetSize() const { return size; }
virtual std::string GetName() const override { return "SpriteComponent"; } virtual std::string GetName() const override { return "SpriteComponent"; }
virtual void Save(YAML::Emitter& out) const override; virtual void Save(YAML::Emitter& out) const override;
virtual void Load(const YAML::Node& node) override; virtual void Load(const YAML::Node& node) override;
private: private:
glm::vec2 size = { 64, 64 }; glm::vec2 size = { 64, 64 };
std::string texturePath;
std::string normalMapPath;
RenderType renderType = RenderType::Lit; RenderType renderType = RenderType::Lit;
uint64_t textureUAID = 0;
uint64_t normalMapUAID = 0;
unsigned int textureID = 0; unsigned int textureID = 0;
unsigned int normalMapID = 0; unsigned int normalMapID = 0;
bool texture_loaded = false; bool texture_loaded = false;
unsigned int LoadTexture(const std::string& path, bool updateSize);
}; };

View File

@ -10,7 +10,6 @@
#include "components/ParticleComponent.h" #include "components/ParticleComponent.h"
#include "components/AnimationComponent.h" #include "components/AnimationComponent.h"
#include "core/utils/FileDialog.h" #include "core/utils/FileDialog.h"
#include "core/utils/Logging.h" #include "core/utils/Logging.h"
@ -489,7 +488,7 @@ void Engine::Init()
// auto sprite = obj->AddComponent<SpriteComponent>(); // auto sprite = obj->AddComponent<SpriteComponent>();
// sprite->SetTexture("C:/Users/spenc/OneDrive/Pictures/textures/ganges_river_pebbles_diff_1k.png"); // 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->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); // objects.push_back(obj);
// } // }
@ -515,22 +514,26 @@ void Engine::Init()
Logger::LogVerbose("Resverving Objects"); Logger::LogVerbose("Resverving Objects");
m_toDraw.reserve(1024); m_toDraw.reserve(1024);
m_scriptUpdates.reserve(256); m_scriptUpdates.reserve(10);
m_collectStack.reserve(1024); m_collectStack.reserve(1024);
m_physicsUpdates.reserve(1024); m_physicsUpdates.reserve(1024);
m_particleUpdates.reserve(1024); m_particleUpdates.reserve(100);
m_animationsUpdates.reserve(100);
Logger::LogInfo("Initialized Engine"); Logger::LogInfo("Initialized Engine");
} }
void Engine::collectObjects(bool playing, const glm::vec2 &camPos, float camZoom) void Engine::collectObjects(bool playing, const glm::vec2 &camPos, float camZoom)
{ {
m_activeCamera = nullptr;
m_toDraw.clear(); m_toDraw.clear();
m_scriptUpdates.clear(); m_scriptUpdates.clear();
m_animationsUpdates.clear();
m_collectStack.clear(); m_collectStack.clear();
m_activeCamera = nullptr;
m_physicsUpdates.clear(); m_physicsUpdates.clear();
m_particleUpdates.clear(); // <-- Add this m_particleUpdates.clear();
const glm::vec2 screenSize = glm::vec2(Renderer::GetSize()); 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<ParticleComponent>()) if (auto particles = obj->GetComponent<ParticleComponent>())
m_particleUpdates.push_back(particles.get()); m_particleUpdates.push_back(particles.get());
if (auto animator = obj->GetComponent<AnimationComponent>())
m_animationsUpdates.push_back(animator.get());
if (playing) if (playing)
{ {
@ -696,7 +701,6 @@ void Engine::Run()
ImGui::Checkbox("Profiler", &g_engineConfig.settings.show_profiler_window); ImGui::Checkbox("Profiler", &g_engineConfig.settings.show_profiler_window);
ImGui::Checkbox("Assets", &g_engineConfig.settings.show_asset_window); ImGui::Checkbox("Assets", &g_engineConfig.settings.show_asset_window);
ImGui::EndMenu(); ImGui::EndMenu();
} }
@ -862,7 +866,6 @@ void Engine::Run()
m_OnUpdateCalls = 0; m_OnUpdateCalls = 0;
if (!g_engineConfig.settings.profile_editor) if (!g_engineConfig.settings.profile_editor)
{ {
profiler.BeginFrame(); profiler.BeginFrame();
@ -888,6 +891,15 @@ void Engine::Run()
} }
profiler.EndSection(); 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.EndSection();
profiler.BeginSection("Render"); profiler.BeginSection("Render");
@ -895,23 +907,22 @@ void Engine::Run()
{ {
const core::types::Vec2 worldPos = obj->GetWorldPosition(); const core::types::Vec2 worldPos = obj->GetWorldPosition();
if (auto spritePtr = obj->GetComponent<SpriteComponent>()) if (auto sprite = obj->GetComponent<SpriteComponent>())
{ {
profiler.BeginSection("Draw Sprite: " + obj->GetName()); profiler.BeginSection("Draw Sprite: " + obj->GetName());
Renderer::DrawSprite(spritePtr.get(), worldPos, cameraZoom, cameraPos); Renderer::DrawSprite(sprite.get(), worldPos, cameraZoom, cameraPos);
profiler.EndSection(); profiler.EndSection();
} }
if (auto animator = obj->GetComponent<AnimationComponent>()) { if (auto animator = obj->GetComponent<AnimationComponent>())
profiler.BeginSection("Draw Animation: " + obj->GetName()); {
profiler.BeginSection("Draw Animator: " + obj->GetName());
Renderer::DrawTextureAtlas(animator->GetAtlas(), animator->GetCurrentFrame(), obj->GetWorldPosition(), obj->GetWorldRotation(), 1.0f); Renderer::DrawAnimator(animator.get(), worldPos, cameraZoom, cameraPos);
profiler.EndSection(); profiler.EndSection();
} }
if (auto particle = obj->GetComponent<ParticleComponent>()) if (auto particle = obj->GetComponent<ParticleComponent>())
{ {
profiler.BeginSection("Draw Particles: " + obj->GetName()); profiler.BeginSection("Draw Particles: " + obj->GetName());
@ -926,7 +937,7 @@ void Engine::Run()
core::types::Vec2 pWorld = p.position + particle->GetOwner()->GetWorldPosition(); core::types::Vec2 pWorld = p.position + particle->GetOwner()->GetWorldPosition();
core::types::Vec2 size = core::types::Vec2(p.size, p.size); 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(); profiler.EndSection();
@ -1117,7 +1128,6 @@ void Engine::SaveScene(const std::string &path)
for (int i = 0; i < SHA256_DIGEST_LENGTH; ++i) for (int i = 0; i < SHA256_DIGEST_LENGTH; ++i)
hashHex << std::hex << std::setw(2) << std::setfill('0') << static_cast<int>(hash[i]); hashHex << std::hex << std::setw(2) << std::setfill('0') << static_cast<int>(hash[i]);
// Build final full YAML output
out << YAML::BeginMap; out << YAML::BeginMap;
out << YAML::Key << "engine_version" << YAML::Value << g_engineConfig.version; out << YAML::Key << "engine_version" << YAML::Value << g_engineConfig.version;
out << YAML::Key << "scene_name" << YAML::Value << std::filesystem::path(path).stem().string(); 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 << "brightness" << YAML::Value << Renderer::GetColorCorrection()->brightness;
out << YAML::Key << "saturation" << YAML::Value << Renderer::GetColorCorrection()->saturation; out << YAML::Key << "saturation" << YAML::Value << Renderer::GetColorCorrection()->saturation;
out << YAML::Key << "gamma" << YAML::Value << Renderer::GetColorCorrection()->gamma; out << YAML::Key << "gamma" << YAML::Value << Renderer::GetColorCorrection()->gamma;
out << YAML::Key << "bloom" << YAML::Value << Renderer::GetColorCorrection()->bloom; out << YAML::Key << "bloom" << YAML::Value << Renderer::GetColorCorrection()->bloom;
out << YAML::Key << "intensity" << YAML::Value << Renderer::GetColorCorrection()->intensity; out << YAML::Key << "intensity" << YAML::Value << Renderer::GetColorCorrection()->intensity;
out << YAML::Key << "threshold" << YAML::Value << Renderer::GetColorCorrection()->threshold; out << YAML::Key << "threshold" << YAML::Value << Renderer::GetColorCorrection()->threshold;
out << YAML::EndMap; out << YAML::EndMap;
AssetManager::Save(out);
out << YAML::EndMap; out << YAML::EndMap;
std::ofstream file(path); std::ofstream file(path);
@ -1147,7 +1157,6 @@ void Engine::SaveScene(const std::string &path)
void Engine::LoadScene(const std::string &path) void Engine::LoadScene(const std::string &path)
{ {
Logger::LogDebug("[LoadScene] Reading Scene File."); Logger::LogDebug("[LoadScene] Reading Scene File.");
YAML::Node root = YAML::LoadFile(path); YAML::Node root = YAML::LoadFile(path);
Logger::LogDebug("[LoadScene] Verifying Scene"); 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."); 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."); Logger::LogDebug("[LoadScene] Reseting Scene.");
objects.clear(); objects.clear();
@ -1196,7 +1211,6 @@ void Engine::LoadScene(const std::string &path)
cc->saturation = data["saturation"].as<float>(); cc->saturation = data["saturation"].as<float>();
if (data["gamma"]) if (data["gamma"])
cc->gamma = data["gamma"].as<float>(); cc->gamma = data["gamma"].as<float>();
if (data["bloom"]) if (data["bloom"])
cc->bloom = data["bloom"].as<bool>(); cc->bloom = data["bloom"].as<bool>();
if (data["intensity"]) if (data["intensity"])
@ -1225,18 +1239,19 @@ void Engine::SaveState()
out << YAML::Key << "brightness" << YAML::Value << Renderer::GetColorCorrection()->brightness; out << YAML::Key << "brightness" << YAML::Value << Renderer::GetColorCorrection()->brightness;
out << YAML::Key << "saturation" << YAML::Value << Renderer::GetColorCorrection()->saturation; out << YAML::Key << "saturation" << YAML::Value << Renderer::GetColorCorrection()->saturation;
out << YAML::Key << "gamma" << YAML::Value << Renderer::GetColorCorrection()->gamma; out << YAML::Key << "gamma" << YAML::Value << Renderer::GetColorCorrection()->gamma;
out << YAML::Key << "bloom" << YAML::Value << Renderer::GetColorCorrection()->bloom; out << YAML::Key << "bloom" << YAML::Value << Renderer::GetColorCorrection()->bloom;
out << YAML::Key << "intensity" << YAML::Value << Renderer::GetColorCorrection()->intensity; out << YAML::Key << "intensity" << YAML::Value << Renderer::GetColorCorrection()->intensity;
out << YAML::Key << "threshold" << YAML::Value << Renderer::GetColorCorrection()->threshold; out << YAML::Key << "threshold" << YAML::Value << Renderer::GetColorCorrection()->threshold;
out << YAML::EndMap; out << YAML::EndMap;
AssetManager::Save(out);
out << YAML::EndMap; out << YAML::EndMap;
savedStateYAML = out.c_str(); savedStateYAML = out.c_str();
Logger::LogVerbose("[SaveState] Scene serialized (%zu bytes)", savedStateYAML.size()); Logger::LogVerbose("[SaveState] Scene serialized (%zu bytes)", savedStateYAML.size());
} }
void Engine::LoadState() void Engine::LoadState()
{ {
if (savedStateYAML.empty()) if (savedStateYAML.empty())
@ -1256,6 +1271,12 @@ void Engine::LoadState()
return; return;
} }
if (root["Assets"])
{
Logger::LogVerbose("[LoadState] Loading Assets");
AssetManager::Load(root["Assets"]);
}
objects.clear(); objects.clear();
const auto &objectArray = root["objects"]; const auto &objectArray = root["objects"];
@ -1263,7 +1284,6 @@ void Engine::LoadState()
{ {
auto obj = std::make_shared<Object>("[DefaultObject]"); auto obj = std::make_shared<Object>("[DefaultObject]");
obj->Load(node); obj->Load(node);
objects.push_back(obj); objects.push_back(obj);
} }
@ -1281,7 +1301,6 @@ void Engine::LoadState()
cc->saturation = data["saturation"].as<float>(); cc->saturation = data["saturation"].as<float>();
if (data["gamma"]) if (data["gamma"])
cc->gamma = data["gamma"].as<float>(); cc->gamma = data["gamma"].as<float>();
if (data["bloom"]) if (data["bloom"])
cc->bloom = data["bloom"].as<bool>(); cc->bloom = data["bloom"].as<bool>();
if (data["intensity"]) if (data["intensity"])

View File

@ -10,6 +10,7 @@ class Object;
class ScriptComponent; class ScriptComponent;
class PhysicsComponent; class PhysicsComponent;
class ParticleComponent; class ParticleComponent;
class AnimationComponent;
class Engine class Engine
{ {
@ -36,6 +37,7 @@ private:
std::vector<Object *> m_toDraw; std::vector<Object *> m_toDraw;
std::vector<ScriptComponent *> m_scriptUpdates; std::vector<ScriptComponent *> m_scriptUpdates;
std::vector<AnimationComponent *> m_animationsUpdates;
int m_OnUpdateCalls; int m_OnUpdateCalls;
std::vector<std::shared_ptr<Object>> m_collectStack; std::vector<std::shared_ptr<Object>> m_collectStack;

View File

@ -77,15 +77,16 @@ struct BatchedSprite
glm::vec4 texCoords; glm::vec4 texCoords;
GLuint textureID; GLuint textureID;
GLuint normalMapID; GLuint normalMapID;
SpriteComponent::RenderType renderType; RenderType renderType;
SpriteComponent *sprite; SpriteComponent *sprite;
}; };
struct SortedDrawEntry struct SortedDrawEntry
{ {
BatchedSprite sprite; BatchedSprite sprite;
Shader *shader; Shader *shader = nullptr;
bool useLighting; bool useLighting = true;
bool usesUV = false;
}; };
std::vector<CachedLightUniforms> s_LightUniforms; std::vector<CachedLightUniforms> s_LightUniforms;
@ -162,25 +163,26 @@ void Renderer::InitQuadBatch()
std::size_t offset = 0; std::size_t offset = 0;
glEnableVertexAttribArray(1); // pos glEnableVertexAttribArray(1);
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, sizeof(QuadInstance), (void *)(offset)); glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, sizeof(QuadInstance), (void *)offsetof(QuadInstance, screenPos));
glVertexAttribDivisor(1, 1); glVertexAttribDivisor(1, 1);
offset += sizeof(glm::vec2);
glEnableVertexAttribArray(2); // size glEnableVertexAttribArray(2);
glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, sizeof(QuadInstance), (void *)(offset)); glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, sizeof(QuadInstance), (void *)offsetof(QuadInstance, size));
glVertexAttribDivisor(2, 1); glVertexAttribDivisor(2, 1);
offset += sizeof(glm::vec2);
glEnableVertexAttribArray(3); // rotation glEnableVertexAttribArray(3);
glVertexAttribPointer(3, 1, GL_FLOAT, GL_FALSE, sizeof(QuadInstance), (void *)(offset)); glVertexAttribPointer(3, 1, GL_FLOAT, GL_FALSE, sizeof(QuadInstance), (void *)offsetof(QuadInstance, rotation));
glVertexAttribDivisor(3, 1); glVertexAttribDivisor(3, 1);
offset += sizeof(float);
glEnableVertexAttribArray(4); // color glEnableVertexAttribArray(4);
glVertexAttribPointer(4, 4, GL_FLOAT, GL_FALSE, sizeof(QuadInstance), (void *)(offset)); glVertexAttribPointer(4, 4, GL_FLOAT, GL_FALSE, sizeof(QuadInstance), (void *)offsetof(QuadInstance, color));
glVertexAttribDivisor(4, 1); glVertexAttribDivisor(4, 1);
glEnableVertexAttribArray(5);
glVertexAttribPointer(5, 1, GL_FLOAT, GL_FALSE, sizeof(QuadInstance), (void *)offsetof(QuadInstance, roundness));
glVertexAttribDivisor(5, 1);
glBindVertexArray(0); 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}); 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) if (s_QuadBatch.size() >= MAX_QUADS)
FlushQuads(); 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 screenPos = (worldPos - cameraPos) * zoom + core::types::Vec2(width * 0.5f, height * 0.5f);
core::types::Vec2 finalSize = size * zoom; 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) 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; SortedDrawEntry drawEntry;
drawEntry.sprite = entry; 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 ? &spriteShader
: &unlitShader; : &unlitShader;
drawEntry.useLighting = (drawEntry.shader == &spriteShader); drawEntry.useLighting = (drawEntry.shader == &spriteShader);
@ -566,7 +584,6 @@ void Renderer::DrawSprite(SpriteComponent *sprite, const glm::vec2 &pos, float z
sortedDrawList.push_back(drawEntry); sortedDrawList.push_back(drawEntry);
} }
void Renderer::DrawTextureAtlas(const TextureAtlas *atlas, int index, const core::types::Vec2 &pos, float rotationDeg, float zoom) void Renderer::DrawTextureAtlas(const TextureAtlas *atlas, int index, const core::types::Vec2 &pos, float rotationDeg, float zoom)
{ {
PROFILE_DEEP_SCOPE("DrawTextureAtlas"); 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(); const core::types::Vec2 uvMax = uvMin + atlas->GetFrameSizeUV();
glm::vec2 screenPos = pos * zoom + glm::vec2(width, height) * 0.5f; 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; BatchedSprite entry;
entry.screenPos = screenPos; entry.screenPos = screenPos;
@ -587,7 +607,7 @@ void Renderer::DrawTextureAtlas(const TextureAtlas *atlas, int index, const core
entry.rotationRad = glm::radians(rotationDeg); entry.rotationRad = glm::radians(rotationDeg);
entry.textureID = tex->GetID(); entry.textureID = tex->GetID();
entry.normalMapID = defaultNormalMap; entry.normalMapID = defaultNormalMap;
entry.renderType = SpriteComponent::RenderType::Unlit; // no lighting for raw atlas drawing entry.renderType = RenderType::Lit;
entry.sprite = nullptr; entry.sprite = nullptr;
entry.texCoords = glm::vec4(uvMin.x, uvMin.y, uvMax.x, uvMax.y); 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.sprite = entry;
drawEntry.shader = &unlitShader; drawEntry.shader = &unlitShader;
drawEntry.useLighting = false; drawEntry.useLighting = false;
drawEntry.usesUV = true; // <- Important!
sortedDrawList.push_back(drawEntry); 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() void Renderer::FlushQuads()
{ {
PROFILE_ENGINE_SCOPE("Renderer::FlushQuads"); PROFILE_ENGINE_SCOPE("Renderer::FlushQuads");
@ -614,16 +675,8 @@ void Renderer::FlushQuads()
glBindVertexArray(s_QuadVAO); glBindVertexArray(s_QuadVAO);
glBindBuffer(GL_ARRAY_BUFFER, s_QuadInstanceVBO); glBindBuffer(GL_ARRAY_BUFFER, s_QuadInstanceVBO);
{
PROFILE_DEEP_SCOPE("Upload");
s_UnlitQuadShader.Use(); std::memcpy(s_QuadMappedPtr, s_QuadBatch.data(), s_QuadBatch.size() * sizeof(QuadInstance));
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));
}
} }
{ {
@ -685,13 +738,26 @@ void Renderer::FlushSprites()
} }
} }
// Uniforms // Common uniforms
currentShader->SetVec2("uPos", entry.sprite.screenPos); currentShader->SetVec2("uPos", entry.sprite.screenPos);
currentShader->SetVec2("uSize", entry.sprite.size); currentShader->SetVec2("uSize", entry.sprite.size);
currentShader->SetFloat("uRotation", entry.sprite.rotationRad); currentShader->SetFloat("uRotation", entry.sprite.rotationRad);
currentShader->SetInt("uTex", 0); 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); glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, entry.sprite.textureID); glBindTexture(GL_TEXTURE_2D, entry.sprite.textureID);

View File

@ -6,6 +6,9 @@
#include "Components/TilemapComponent.h" #include "Components/TilemapComponent.h"
#include "Components/SpriteComponent.h" #include "Components/SpriteComponent.h"
#include "Components/SpriteComponent.h"
#include "Components/AnimationComponent.h"
#include "core/utils/EngineConfig.h" #include "core/utils/EngineConfig.h"
#include "utils/Shader.h" #include "utils/Shader.h"
#include "core/utils/Profiler.h" #include "core/utils/Profiler.h"
@ -20,7 +23,7 @@ struct ColorCorrection
float gamma = 1.0f; float gamma = 1.0f;
bool bloom = true; bool bloom = true;
float threshold = 0.2f; float threshold = 1.0f;
float intensity = 1.2f; float intensity = 1.2f;
void Upload(Shader &shader) const void Upload(Shader &shader) const
@ -41,10 +44,11 @@ struct Light
struct QuadInstance struct QuadInstance
{ {
core::types::Vec2 pos; core::types::Vec2 screenPos;
core::types::Vec2 size; core::types::Vec2 size;
float rotation; float rotation;
core::types::Color color; core::types::Color color;
float roundness = 0.0f;
}; };
class Renderer class Renderer
@ -80,10 +84,24 @@ public:
static void InitQuadBatch(); 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 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 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(); static void FlushQuads();
private: private:

View File

@ -9,62 +9,40 @@ namespace core
namespace types namespace types
{ {
struct Vec2i;
struct Vec2 struct Vec2
{ {
float x{0}, y{0}; float x{0}, y{0};
// Constructors
Vec2() = default; Vec2() = default;
Vec2(float x, float y) : x(x), y(y) {} Vec2(float x, float y) : x(x), y(y) {}
Vec2(float v) : x(v), y(v) {} Vec2(float v) : x(v), y(v) {}
Vec2(const glm::vec2 &v) : x(v.x), y(v.y) {} 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}; } 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-(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/(float scalar) const { return {x / scalar, y / scalar}; } Vec2 operator/(float scalar) const { return {x / scalar, y / scalar}; }
Vec2 &operator+=(const Vec2 &rhs) Vec2 operator*(const Vec2 &rhs) const { return {x * rhs.x, y * rhs.y}; }
{
x += rhs.x; Vec2 &operator+=(const Vec2 &rhs) { x += rhs.x; y += rhs.y; return *this; }
y += rhs.y; Vec2 &operator-=(const Vec2 &rhs) { x -= rhs.x; y -= rhs.y; return *this; }
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)
{
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}; } 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 x == rhs.x && y == rhs.y; }
bool operator!=(const Vec2 &rhs) const { return !(*this == rhs); } bool operator!=(const Vec2 &rhs) const { return !(*this == rhs); }
// Length
float Length() const { return std::sqrt(x * x + y * y); } float Length() const { return std::sqrt(x * x + y * y); }
float LengthSquared() const { return x * x + y * y; } float LengthSquared() const { return x * x + y * y; }
// Normalization
Vec2 Normalized() const Vec2 Normalized() const
{ {
float len = Length(); float len = Length();
@ -81,40 +59,61 @@ namespace core
} }
} }
// Dot product
float Dot(const Vec2 &rhs) const { return x * rhs.x + y * rhs.y; } float Dot(const Vec2 &rhs) const { return x * rhs.x + y * rhs.y; }
// Clamp
void Clamp(const Vec2 &min, const Vec2 &max) void Clamp(const Vec2 &min, const Vec2 &max)
{ {
x = std::max(min.x, std::min(x, max.x)); x = std::max(min.x, std::min(x, max.x));
y = std::max(min.y, std::min(y, max.y)); y = std::max(min.y, std::min(y, max.y));
} }
// Lerp
static Vec2 Lerp(const Vec2 &a, const Vec2 &b, float t) static Vec2 Lerp(const Vec2 &a, const Vec2 &b, float t)
{ {
return a + (b - a) * t; return a + (b - a) * t;
} }
// Distance
static float Distance(const Vec2 &a, const Vec2 &b) static float Distance(const Vec2 &a, const Vec2 &b)
{ {
return (a - b).Length(); return (a - b).Length();
} }
// Serialization helpers (optional)
friend std::ostream &operator<<(std::ostream &os, const Vec2 &v) friend std::ostream &operator<<(std::ostream &os, const Vec2 &v)
{ {
return os << "(" << v.x << ", " << v.y << ")"; return os << "(" << v.x << ", " << v.y << ")";
} }
}; };
// Scalar * Vec2 support struct Vec2i
inline Vec2 operator*(float scalar, const Vec2 &v)
{ {
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<int>(v.x)), y(static_cast<int>(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 types
} // namespace core } // namespace core

View File

@ -1,167 +1,167 @@
#pragma once //#pragma once
#include <cstdlib> //#include <cstdlib>
#include <cstring> //#include <cstring>
#include <cassert> //#include <cassert>
#include <new> //#include <new>
#include <utility> //#include <utility>
#include <algorithm> //#include <algorithm>
#include <type_traits> //#include <type_traits>
//
#ifndef FV_ASSERT //#ifndef FV_ASSERT
#define FV_ASSERT(cond) assert(cond) //#define FV_ASSERT(cond) assert(cond)
#endif //#endif
//
template<typename T, size_t SBO_CAP = 16> //template<typename T, size_t SBO_CAP = 16>
class FastVector { //class FastVector {
using StorageT = typename std::aligned_storage<sizeof(T), alignof(T)>::type; // using StorageT = typename std::aligned_storage<sizeof(T), alignof(T)>::type;
//
StorageT sbo_[SBO_CAP]; // StorageT sbo_[SBO_CAP];
T* data_ = reinterpret_cast<T*>(sbo_); // T* data_ = reinterpret_cast<T*>(sbo_);
size_t size_ = 0; // size_t size_ = 0;
size_t capacity_ = SBO_CAP; // size_t capacity_ = SBO_CAP;
bool heapAllocated_ = false; // bool heapAllocated_ = false;
//
inline void reallocate(size_t newCap) { // inline void reallocate(size_t newCap) {
T* newData = reinterpret_cast<T*>(std::malloc(newCap * sizeof(T))); // T* newData = reinterpret_cast<T*>(std::malloc(newCap * sizeof(T)));
if (!newData) std::abort(); // if (!newData) std::abort();
//
if constexpr (std::is_trivially_copyable_v<T>) { // if constexpr (std::is_trivially_copyable_v<T>) {
std::memcpy(newData, data_, size_ * sizeof(T)); // std::memcpy(newData, data_, size_ * sizeof(T));
} else { // } else {
std::uninitialized_copy(data_, data_ + size_, newData); // std::uninitialized_copy(data_, data_ + size_, newData);
std::destroy(data_, data_ + size_); // std::destroy(data_, data_ + size_);
} // }
//
if (heapAllocated_) std::free(data_); // if (heapAllocated_) std::free(data_);
data_ = newData; // data_ = newData;
capacity_ = newCap; // capacity_ = newCap;
heapAllocated_ = true; // heapAllocated_ = true;
} // }
//
public: //public:
inline FastVector() = default; // inline FastVector() = default;
//
inline ~FastVector() { // inline ~FastVector() {
std::destroy(data_, data_ + size_); // std::destroy(data_, data_ + size_);
if (heapAllocated_) std::free(data_); // if (heapAllocated_) std::free(data_);
} // }
//
// Copy constructor // // Copy constructor
FastVector(const FastVector& other) { // FastVector(const FastVector& other) {
reserve(other.size_); // reserve(other.size_);
if constexpr (std::is_trivially_copyable_v<T>) { // if constexpr (std::is_trivially_copyable_v<T>) {
std::memcpy(data_, other.data_, other.size_ * sizeof(T)); // std::memcpy(data_, other.data_, other.size_ * sizeof(T));
} else { // } else {
std::uninitialized_copy(other.data_, other.data_ + other.size_, data_); // std::uninitialized_copy(other.data_, other.data_ + other.size_, data_);
} // }
size_ = other.size_; // size_ = other.size_;
} // }
//
// Move constructor // // Move constructor
FastVector(FastVector&& other) noexcept { // FastVector(FastVector&& other) noexcept {
if (other.heapAllocated_) { // if (other.heapAllocated_) {
data_ = other.data_; // data_ = other.data_;
size_ = other.size_; // size_ = other.size_;
capacity_ = other.capacity_; // capacity_ = other.capacity_;
heapAllocated_ = true; // heapAllocated_ = true;
} else { // } else {
std::uninitialized_move(other.data_, other.data_ + other.size_, data_); // std::uninitialized_move(other.data_, other.data_ + other.size_, data_);
} // }
other.data_ = reinterpret_cast<T*>(other.sbo_); // other.data_ = reinterpret_cast<T*>(other.sbo_);
other.size_ = 0; // other.size_ = 0;
other.capacity_ = SBO_CAP; // other.capacity_ = SBO_CAP;
other.heapAllocated_ = false; // other.heapAllocated_ = false;
} // }
//
// Copy assignment // // Copy assignment
FastVector& operator=(const FastVector& other) { // FastVector& operator=(const FastVector& other) {
if (this != &other) { // if (this != &other) {
clear(); // clear();
reserve(other.size_); // reserve(other.size_);
if constexpr (std::is_trivially_copyable_v<T>) { // if constexpr (std::is_trivially_copyable_v<T>) {
std::memcpy(data_, other.data_, other.size_ * sizeof(T)); // std::memcpy(data_, other.data_, other.size_ * sizeof(T));
} else { // } else {
std::uninitialized_copy(other.data_, other.data_ + other.size_, data_); // std::uninitialized_copy(other.data_, other.data_ + other.size_, data_);
} // }
size_ = other.size_; // size_ = other.size_;
} // }
return *this; // return *this;
} // }
//
// Move assignment // // Move assignment
FastVector& operator=(FastVector&& other) noexcept { // FastVector& operator=(FastVector&& other) noexcept {
if (this != &other) { // if (this != &other) {
clear(); // clear();
if (heapAllocated_) std::free(data_); // if (heapAllocated_) std::free(data_);
//
if (other.heapAllocated_) { // if (other.heapAllocated_) {
data_ = other.data_; // data_ = other.data_;
size_ = other.size_; // size_ = other.size_;
capacity_ = other.capacity_; // capacity_ = other.capacity_;
heapAllocated_ = true; // heapAllocated_ = true;
} else { // } else {
std::uninitialized_move(other.data_, other.data_ + other.size_, data_); // std::uninitialized_move(other.data_, other.data_ + other.size_, data_);
} // }
//
other.data_ = reinterpret_cast<T*>(other.sbo_); // other.data_ = reinterpret_cast<T*>(other.sbo_);
other.size_ = 0; // other.size_ = 0;
other.capacity_ = SBO_CAP; // other.capacity_ = SBO_CAP;
other.heapAllocated_ = false; // other.heapAllocated_ = false;
} // }
return *this; // return *this;
} // }
//
inline void push_back(const T& val) { // inline void push_back(const T& val) {
if (size_ == capacity_) reallocate(capacity_ * 2); // if (size_ == capacity_) reallocate(capacity_ * 2);
new (data_ + size_) T(val); // new (data_ + size_) T(val);
++size_; // ++size_;
} // }
//
inline void push_back(T&& val) { // inline void push_back(T&& val) {
if (size_ == capacity_) reallocate(capacity_ * 2); // if (size_ == capacity_) reallocate(capacity_ * 2);
new (data_ + size_) T(std::move(val)); // new (data_ + size_) T(std::move(val));
++size_; // ++size_;
} // }
//
inline void pop_back() { // inline void pop_back() {
FV_ASSERT(size_ > 0); // FV_ASSERT(size_ > 0);
--size_; // --size_;
std::destroy_at(data_ + size_); // std::destroy_at(data_ + size_);
} // }
//
inline void clear() { // inline void clear() {
std::destroy(data_, data_ + size_); // std::destroy(data_, data_ + size_);
size_ = 0; // size_ = 0;
} // }
//
inline void reserve(size_t newCap) { // inline void reserve(size_t newCap) {
if (newCap > capacity_) reallocate(newCap); // if (newCap > capacity_) reallocate(newCap);
} // }
//
inline void resize(size_t newSize) { // inline void resize(size_t newSize) {
if (newSize > capacity_) reallocate(newSize); // if (newSize > capacity_) reallocate(newSize);
if (newSize > size_) { // if (newSize > size_) {
std::uninitialized_value_construct(data_ + size_, data_ + newSize); // std::uninitialized_value_construct(data_ + size_, data_ + newSize);
} else { // } else {
std::destroy(data_ + newSize, data_ + size_); // std::destroy(data_ + newSize, data_ + size_);
} // }
size_ = newSize; // size_ = newSize;
} // }
//
inline T& operator[](size_t i) { // inline T& operator[](size_t i) {
FV_ASSERT(i < size_); // FV_ASSERT(i < size_);
return data_[i]; // return data_[i];
} // }
//
inline const T& operator[](size_t i) const { // inline const T& operator[](size_t i) const {
FV_ASSERT(i < size_); // FV_ASSERT(i < size_);
return data_[i]; // return data_[i];
} // }
//
inline T* data() { return data_; } // inline T* data() { return data_; }
inline const T* data() const { return data_; } // inline const T* data() const { return data_; }
//
inline size_t size() const { return size_; } // inline size_t size() const { return size_; }
inline size_t capacity() const { return capacity_; } // inline size_t capacity() const { return capacity_; }
inline bool empty() const { return size_ == 0; } // inline bool empty() const { return size_ == 0; }
}; //};

View File

@ -0,0 +1,243 @@
#include "AssetManager.h"
#include "utils.h"
#include "../../Renderer.h"
#define STB_IMAGE_IMPLEMENTATION
#include <stb_image.h>
#include <string>
#include <random>
#include <mutex>
#include <functional> // for std::hash
std::unordered_map<uint64_t, AssetInfo> AssetManager::s_Assets;
std::mutex AssetManager::s_Mutex;
uint64_t AssetManager::s_NextUAID = 1;
inline static std::unordered_map<std::string, uint64_t> 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<std::mutex> lock(s_Mutex);
static std::random_device rd;
static std::mt19937 gen(rd());
static std::uniform_int_distribution<int> dist(0, 9);
std::string digits;
digits.reserve(32);
for (int i = 0; i < 32; ++i)
digits += static_cast<char>('0' + dist(gen));
return std::hash<std::string>{}(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<std::mutex> 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<std::mutex> 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<std::mutex> 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<std::mutex> 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<std::mutex> 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<std::mutex> lock(s_Mutex);
for (const auto &[id, asset] : s_Assets)
if (asset.path == path)
return &asset;
return nullptr;
}
const std::unordered_map<uint64_t, AssetInfo> &AssetManager::GetAllAssets()
{
return s_Assets; // Assume read-only external usage
}
void AssetManager::UnloadAsset(uint64_t uaid)
{
std::lock_guard<std::mutex> 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<std::mutex> 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<std::mutex> 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<int>(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<uint64_t>();
asset.path = item["path"].as<std::string>();
asset.filename = item["filename"].as<std::string>();
asset.filetype = item["filetype"].as<std::string>();
asset.type = static_cast<AssetType>(item["type"].as<int>());
const auto &size = item["size"];
asset.size = {size[0].as<float>(), size[1].as<float>()};
asset.loaded = false;
{
std::lock_guard<std::mutex> 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);
}
}
}

View File

@ -0,0 +1,50 @@
#pragma once
#include <string>
#include <unordered_map>
#include <mutex>
#include <vector>
#include <future>
#include <yaml-cpp/yaml.h>
#include "../types/vec2.h"
#include <GL/glew.h>
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<uint64_t, AssetInfo>& 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<uint64_t, AssetInfo> 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);
};

View File

@ -7,7 +7,7 @@
USER_SETTING(profile_enabled, bool, true) \ USER_SETTING(profile_enabled, bool, true) \
USER_SETTING(show_color_correction_window, bool, false) \ USER_SETTING(show_color_correction_window, bool, false) \
USER_SETTING(show_profiler_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(profile_deep, bool, false) \
USER_SETTING(show_asset_window, bool, false) \ USER_SETTING(show_asset_window, bool, false) \
USER_SETTING(profile_gpu, bool, false) USER_SETTING(profile_gpu, bool, false)

View File

@ -1,19 +1,41 @@
#include "Texture.h" #include "Texture.h"
#include <GL/glew.h> #include "AssetManager.h"
#include <stb_image.h> #include "Logging.h"
#include <iostream>
#include "utils.h"
Texture::Texture(const std::string &path) 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 unsigned int Texture::GetID() const
{ {
return id; return id;

View File

@ -1,13 +1,26 @@
#pragma once #pragma once
#include <string> #include <string>
#include "../types/all.h"
enum class RenderType {
Unlit,
Lit
};
class Texture { class Texture {
public: public:
Texture(const std::string& path); Texture(const std::string& path);
Texture(uint64_t uaid); // New constructor using UAID
~Texture(); ~Texture();
unsigned int GetID() const; unsigned int GetID() const;
void SetSize(core::types::Vec2 newSize) {size = newSize;};
core::types::Vec2 GetSize() {return size;};
private: private:
unsigned int id = 0; unsigned int id = 0;
core::types::Vec2 size;
}; };

View File

@ -6,36 +6,62 @@
struct TextureAtlas struct TextureAtlas
{ {
std::shared_ptr<Texture> texture; std::shared_ptr<Texture> texture;
int columns = 1; int frameWidth = 1;
int rows = 1; int frameHeight = 1;
TextureAtlas() = default; TextureAtlas() = default;
TextureAtlas(std::shared_ptr<Texture> 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<Texture> 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); return core::types::Vec2(0.0f);
}
int x = index % columns; int texWidth = texture->GetSize().x;
int y = index / columns; int texHeight = texture->GetSize().y;
float u = static_cast<float>(x) / static_cast<float>(columns); int cols = texWidth / frameWidth;
float v = static_cast<float>(y) / static_cast<float>(rows); 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); return core::types::Vec2(u, v);
} }
core::types::Vec2 GetFrameSizeUV() const 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<float>(frameWidth) / texture->GetSize().x,
static_cast<float>(frameHeight) / texture->GetSize().y
);
} }
int GetTotalFrames() const 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;
} }
}; };

View File

@ -12,6 +12,44 @@ std::unordered_map<std::string, ImageCacheEntry> 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) GLuint LoadTextureIfNeeded(const std::string &path)
{ {
auto [it, inserted] = textureCache.try_emplace(path, ImageCacheEntry{}); auto [it, inserted] = textureCache.try_emplace(path, ImageCacheEntry{});
@ -39,7 +77,8 @@ GLuint LoadTextureIfNeeded(const std::string &path)
it->second = { id, imageSize }; 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; return id;
} }

View File

@ -11,6 +11,8 @@
#include "FileDialog.h" #include "FileDialog.h"
#include "EngineConfig.h" #include "EngineConfig.h"
#include "AssetManager.h"
struct ImageCacheEntry { struct ImageCacheEntry {
unsigned int textureID; unsigned int textureID;
glm::vec2 size; glm::vec2 size;
@ -26,6 +28,8 @@ std::string GetFilenameFromPath(const std::string& path);
GLuint LoadTextureIfNeeded(const std::string& path); GLuint LoadTextureIfNeeded(const std::string& path);
ImageCacheEntry LoadImageCache(const std::string& path);
GLuint EngineLoadTextureIfNeeded(const std::string &path); GLuint EngineLoadTextureIfNeeded(const std::string &path);

View File

@ -2,11 +2,10 @@
#include <imgui.h> #include <imgui.h>
#include "../../core/utils/EngineConfig.h" #include "../../core/utils/EngineConfig.h"
#include "../../core/utils/utils.h" #include "../../core/utils/utils.h"
#include "../../core/utils/AssetManager.h"
#include "../../Renderer.h" #include "../../Renderer.h"
#include "../../core/utils/Logging.h" #include "../../core/utils/Logging.h"
extern std::unordered_map<std::string, ImageCacheEntry> textureCache;
static std::string assetSearchQuery; static std::string assetSearchQuery;
void ShowAssetBrowser() void ShowAssetBrowser()
@ -23,13 +22,10 @@ void ShowAssetBrowser()
std::string path = OpenFileDialog(FileDialogType::Images); std::string path = OpenFileDialog(FileDialogType::Images);
if (!path.empty()) if (!path.empty())
{ {
LoadTextureIfNeeded(path); AssetManager::LoadAssetAsync(path, AssetType::Image);
} }
} }
ImGui::Separator(); ImGui::Separator();
char buffer[256] = {}; char buffer[256] = {};
strncpy(buffer, assetSearchQuery.c_str(), sizeof(buffer) - 1); strncpy(buffer, assetSearchQuery.c_str(), sizeof(buffer) - 1);
@ -40,7 +36,6 @@ void ShowAssetBrowser()
} }
ImGui::Separator(); ImGui::Separator();
ImGui::BeginChild("##AssetScroll", ImVec2(0, 0), true); ImGui::BeginChild("##AssetScroll", ImVec2(0, 0), true);
const float padding = 8.0f; const float padding = 8.0f;
@ -55,46 +50,51 @@ void ShowAssetBrowser()
ImGui::Columns(columns, nullptr, false); ImGui::Columns(columns, nullptr, false);
int idx = 0; int idx = 0;
for (auto it = textureCache.begin(); it != textureCache.end();) for (const auto& [uaid, asset] : AssetManager::GetAllAssets())
{ {
const std::string &path = it->first; if (asset.type != AssetType::Image || !asset.loaded)
auto &entry = it->second; continue;
if (!assetSearchQuery.empty() && 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; continue;
} }
ImGui::PushID(idx++); ImGui::PushID(idx++);
std::string displayName = GetFilenameFromPath(path); std::string displayName = GetFilenameFromPath(asset.path);
if (ImGui::ImageButton("##Image", ImGui::Image((ImTextureID)(intptr_t)asset.textureID,
(ImTextureID)(intptr_t)entry.textureID, ImVec2(thumbnailSize, thumbnailSize));
ImVec2(thumbnailSize, thumbnailSize),
ImVec2(0, 0), ImVec2(1, 1))) 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()) if (ImGui::IsItemHovered())
{ {
ImGui::BeginTooltip(); ImGui::BeginTooltip();
ImGui::Text("Path: %s", path.c_str()); ImGui::Text("Path: %s", asset.path.c_str());
ImGui::Text("Texture ID: %u", entry.textureID); ImGui::Text("UAID: %llu", asset.uaid);
ImGui::Text("Size: %dx%d", entry.size.x, entry.size.y); ImGui::Text("Texture ID: %u", asset.textureID);
ImGui::Text("Size: (%.0f, %.0f)", asset.size.x, asset.size.y);
ImGui::EndTooltip(); ImGui::EndTooltip();
} }
// Right-click menu
if (ImGui::BeginPopupContextItem("AssetContext")) if (ImGui::BeginPopupContextItem("AssetContext"))
{ {
if (ImGui::MenuItem("Unload")) if (ImGui::MenuItem("Unload"))
{ {
Logger::LogInfo("[AssetBrowser] Unloaded: %s", path.c_str()); Logger::LogInfo("[AssetBrowser] Unloaded: %s", asset.path.c_str());
it = textureCache.erase(it); AssetManager::UnloadAsset(uaid);
ImGui::EndPopup(); ImGui::EndPopup();
ImGui::PopID(); ImGui::PopID();
continue; continue;
@ -102,28 +102,20 @@ void ShowAssetBrowser()
if (ImGui::MenuItem("Copy Path")) 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(); 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::TextWrapped("%s", displayName.c_str());
ImGui::NextColumn(); ImGui::NextColumn();
ImGui::PopID(); ImGui::PopID();
++it;
} }
ImGui::Columns(1); ImGui::Columns(1);

View File

@ -119,20 +119,23 @@ void DrawInspectorUI(std::shared_ptr<Object> selected)
const char *renderTypes[] = {"Unlit", "Lit"}; const char *renderTypes[] = {"Unlit", "Lit"};
int currentTypeIndex = static_cast<int>(sprite->GetRenderType()); int currentTypeIndex = static_cast<int>(sprite->GetRenderType());
if (ImGui::Combo("Render Type", &currentTypeIndex, renderTypes, IM_ARRAYSIZE(renderTypes))) if (ImGui::Combo("Render Type", &currentTypeIndex, renderTypes, IM_ARRAYSIZE(renderTypes)))
sprite->SetRenderType(static_cast<SpriteComponent::RenderType>(currentTypeIndex)); sprite->SetRenderType(static_cast<RenderType>(currentTypeIndex));
ImGui::SeparatorText("Texture"); 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 (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; if (payload->DataSize == sizeof(uint64_t))
sprite->SetTexture(dropped); {
uint64_t uaid = *reinterpret_cast<const uint64_t *>(payload->Data);
sprite->SetTexture(uaid);
}
} }
ImGui::EndDragDropTarget(); ImGui::EndDragDropTarget();
} }
@ -141,34 +144,39 @@ void DrawInspectorUI(std::shared_ptr<Object> selected)
{ {
auto path = OpenFileDialog(FileDialogType::Images); auto path = OpenFileDialog(FileDialogType::Images);
if (!path.empty()) if (!path.empty())
sprite->SetTexture(path); sprite->SetTexture(path); // Auto-registers and sets UAID
} }
} }
ImGui::SeparatorText("Normal Map"); 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 (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; if (payload->DataSize == sizeof(uint64_t))
sprite->SetNormalMap(dropped); {
uint64_t uaid = *reinterpret_cast<const uint64_t *>(payload->Data);
sprite->SetNormalMap(uaid);
}
} }
ImGui::EndDragDropTarget(); ImGui::EndDragDropTarget();
} }
if (ImGui::SmallButton("Load##SpriteNorm")) if (ImGui::SmallButton("Load##SpriteNorm"))
{ {
auto path = OpenFileDialog(FileDialogType::Images); auto path = OpenFileDialog(FileDialogType::Images);
if (!path.empty()) if (!path.empty())
sprite->SetNormalMap(path); sprite->SetNormalMap(path); // Auto-registers and sets UAID
} }
} }
ImGui::SeparatorText("Info"); ImGui::SeparatorText("Info");
// — Size Display & Remove —
glm::vec2 size = sprite->GetSize(); glm::vec2 size = sprite->GetSize();
ImGui::Text("Size: %.0f × %.0f", size.x, size.y); ImGui::Text("Size: %.0f × %.0f", size.x, size.y);
@ -252,51 +260,61 @@ void DrawInspectorUI(std::shared_ptr<Object> selected)
if (ImGui::Button("Remove ScriptComponent")) if (ImGui::Button("Remove ScriptComponent"))
selected->RemoveComponent<ScriptComponent>(); selected->RemoveComponent<ScriptComponent>();
} }
if (auto anim = selected->GetComponent<AnimationComponent>()) if (auto anim = selected->GetComponent<AnimationComponent>())
{ {
ImGui::SeparatorText("Animation Component"); ImGui::SeparatorText("Animation Component");
static int columns = anim->GetAtlas()->columns; static int frameWidth = anim->GetAtlas()->frameWidth;
static int rows = anim->GetAtlas()->rows; static int frameHeight = anim->GetAtlas()->frameHeight;
static float frameDuration = anim->GetFrameDuration(); static float frameDuration = anim->GetFrameDuration();
static int frameIndex = anim->GetCurrentFrame(); static int frameIndex = anim->GetCurrentFrame();
static int startFrame = 0;
static int endFrame = 0;
// — Texture Preview & Selector —
ImGui::SeparatorText("Texture Atlas"); ImGui::SeparatorText("Texture Atlas");
{ {
std::string texFile = GetFilenameFromPath(anim->GetTexturePath()); std::string texFile = "(None)";
ImGui::Text(texFile.c_str()); if (const auto* asset = AssetManager::GetAssetByID(anim->GetTextureUAID()))
texFile = GetFilenameFromPath(asset->path);
ImGui::Text("%s", texFile.c_str());
if (ImGui::BeginDragDropTarget()) 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; uint64_t droppedUAID = *(const uint64_t*)payload->Data;
anim->SetTextureAtlas(dropped, columns, rows, frameDuration); anim->SetTextureAtlas(droppedUAID, frameWidth, frameHeight, frameDuration, startFrame, endFrame);
} }
ImGui::EndDragDropTarget(); ImGui::EndDragDropTarget();
} }
if (ImGui::SmallButton("Load##AnimTex")) if (ImGui::SmallButton("Load##AnimTex"))
{ {
auto path = OpenFileDialog(FileDialogType::Images); std::string path = OpenFileDialog(FileDialogType::Images);
if (!path.empty()) if (const auto *asset = AssetManager::GetAssetByPath(path))
anim->SetTextureAtlas(path, columns, rows, frameDuration); anim->SetTextureAtlas(asset->uaid, frameWidth, frameHeight, frameDuration, startFrame, endFrame);
} }
} }
// — Grid settings —
ImGui::InputInt("Columns", &columns); ImGui::InputInt("Texel Width", &frameWidth);
ImGui::InputInt("Rows", &rows); ImGui::InputInt("Texel Height", &frameHeight);
ImGui::InputFloat("Frame Duration", &frameDuration, 0.01f, 0.1f, "%.3f"); 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"); ImGui::SeparatorText("Playback");
bool isPlaying = anim->IsPlaying(); bool isPlaying = anim->IsPlaying();
@ -318,7 +336,7 @@ void DrawInspectorUI(std::shared_ptr<Object> selected)
} }
// Frame scrubber // Frame scrubber
int maxFrame = columns * rows - 1; int maxFrame = anim->GetAtlas()->GetTotalFrames() - 1;
frameIndex = anim->GetCurrentFrame(); frameIndex = anim->GetCurrentFrame();
if (ImGui::SliderInt("Current Frame", &frameIndex, 0, maxFrame)) if (ImGui::SliderInt("Current Frame", &frameIndex, 0, maxFrame))
{ {
@ -331,14 +349,13 @@ void DrawInspectorUI(std::shared_ptr<Object> selected)
ImGui::SeparatorText("Atlas Viewer"); ImGui::SeparatorText("Atlas Viewer");
const float previewSize = 128.0f; const float previewSize = 128.0f;
ImVec2 uv0, uv1;
core::types::Vec2 uvMin = anim->GetAtlas()->GetFrameUV(frameIndex); core::types::Vec2 uvMin = anim->GetAtlas()->GetFrameUV(frameIndex);
core::types::Vec2 uvSize = anim->GetAtlas()->GetFrameSizeUV(); 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(); ImGui::Separator();
@ -367,6 +384,10 @@ void DrawInspectorUI(std::shared_ptr<Object> selected)
ImGui::ColorEdit4("Start Color", &settings.startColor.r); ImGui::ColorEdit4("Start Color", &settings.startColor.r);
ImGui::ColorEdit4("End Color", &settings.endColor.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("Loop", &settings.loop);
ImGui::Checkbox("Burst", &settings.burst); ImGui::Checkbox("Burst", &settings.burst);