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

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\editor\windows\AssetBrowser.cpp -o src\build\editor\windows\AssetBrowser.o
[COMPILE] g++ -std=c++20 -Wall -g -Isrc/include -Isrc/include/lua -Isrc/vendor -Isrc/vendor/imgui -Isrc/vendor/box2d -IC:/msys64/mingw64/include -IC:\msys64\mingw64\lib\libyaml-cpp.a -Isrc\vendor\imgui -MMD -MP -c src\src\utils\Shader.cpp -o src\build\utils\Shader.o
[COMPILE] g++ -std=c++20 -Wall -g -Isrc/include -Isrc/include/lua -Isrc/vendor -Isrc/vendor/imgui -Isrc/vendor/box2d -IC:/msys64/mingw64/include -IC:\msys64\mingw64\lib\libyaml-cpp.a -Isrc\vendor\imgui -MMD -MP -c src\src\Components\ScriptComponent.cpp -o src\build\Components\ScriptComponent.o
[COMPILE] g++ -std=c++20 -Wall -g -Isrc/include -Isrc/include/lua -Isrc/vendor -Isrc/vendor/imgui -Isrc/vendor/box2d -IC:/msys64/mingw64/include -IC:\msys64\mingw64\lib\libyaml-cpp.a -Isrc\vendor\imgui -MMD -MP -c src\src\Components\TilemapComponent.cpp -o src\build\Components\TilemapComponent.o
[COMPILE] g++ -std=c++20 -Wall -g -Isrc/include -Isrc/include/lua -Isrc/vendor -Isrc/vendor/imgui -Isrc/vendor/box2d -IC:/msys64/mingw64/include -IC:\msys64\mingw64\lib\libyaml-cpp.a -Isrc\vendor\imgui -MMD -MP -c src\src\core\utils\Profiler.cpp -o src\build\core\utils\Profiler.o
[COMPILE] g++ -std=c++20 -Wall -g -Isrc/include -Isrc/include/lua -Isrc/vendor -Isrc/vendor/imgui -Isrc/vendor/box2d -IC:/msys64/mingw64/include -IC:\msys64\mingw64\lib\libyaml-cpp.a -Isrc\vendor\imgui -MMD -MP -c src\src\Renderer.cpp -o src\build\Renderer.o
[COMPILE] g++ -std=c++20 -Wall -g -Isrc/include -Isrc/include/lua -Isrc/vendor -Isrc/vendor/imgui -Isrc/vendor/box2d -IC:/msys64/mingw64/include -IC:\msys64\mingw64\lib\libyaml-cpp.a -Isrc\vendor\imgui -MMD -MP -c src\src\Components\ParticleComponent.cpp -o src\build\Components\ParticleComponent.o
[COMPILE] g++ -std=c++20 -Wall -g -Isrc/include -Isrc/include/lua -Isrc/vendor -Isrc/vendor/imgui -Isrc/vendor/box2d -IC:/msys64/mingw64/include -IC:\msys64\mingw64\lib\libyaml-cpp.a -Isrc\vendor\imgui -MMD -MP -c src\src\Components\AnimationComponent.cpp -o src\build\Components\AnimationComponent.o
[COMPILE] g++ -std=c++20 -Wall -g -Isrc/include -Isrc/include/lua -Isrc/vendor -Isrc/vendor/imgui -Isrc/vendor/box2d -IC:/msys64/mingw64/include -IC:\msys64\mingw64\lib\libyaml-cpp.a -Isrc\vendor\imgui -MMD -MP -c src\src\editor\windows\Inspector.cpp -o src\build\editor\windows\Inspector.o
[COMPILE] g++ -std=c++20 -Wall -g -Isrc/include -Isrc/include/lua -Isrc/vendor -Isrc/vendor/imgui -Isrc/vendor/box2d -IC:/msys64/mingw64/include -IC:\msys64\mingw64\lib\libyaml-cpp.a -Isrc\vendor\imgui -MMD -MP -c src\src\core\utils\EngineConfig.cpp -o src\build\core\utils\EngineConfig.o
[COMPILE] g++ -std=c++20 -Wall -g -Isrc/include -Isrc/include/lua -Isrc/vendor -Isrc/vendor/imgui -Isrc/vendor/box2d -IC:/msys64/mingw64/include -IC:\msys64\mingw64\lib\libyaml-cpp.a -Isrc\vendor\imgui -MMD -MP -c src\src\core\utils\utils.cpp -o src\build\core\utils\utils.o
[COMPILE] g++ -std=c++20 -Wall -g -Isrc/include -Isrc/include/lua -Isrc/vendor -Isrc/vendor/imgui -Isrc/vendor/box2d -IC:/msys64/mingw64/include -IC:\msys64\mingw64\lib\libyaml-cpp.a -Isrc\vendor\imgui -MMD -MP -c src\src\Components\SpriteComponent.cpp -o src\build\Components\SpriteComponent.o
[COMPILE] g++ -std=c++20 -Wall -g -Isrc/include -Isrc/include/lua -Isrc/vendor -Isrc/vendor/imgui -Isrc/vendor/box2d -IC:/msys64/mingw64/include -IC:\msys64\mingw64\lib\libyaml-cpp.a -Isrc\vendor\imgui -MMD -MP -c src\src\Engine.cpp -o src\build\Engine.o
[LINK] g++ src\build\Engine.o src\build\main.o src\build\Renderer.o src\build\Components\AnimationComponent.o src\build\Components\CameraComponent.o src\build\Components\LightComponent.o src\build\Components\ParticleComponent.o src\build\Components\PhysicsComponent.o src\build\Components\ScriptComponent.o src\build\Components\SpriteComponent.o src\build\Components\TextComonent.o src\build\Components\TilemapComponent.o src\build\core\utils\AssetLoader.o src\build\core\utils\EngineConfig.o src\build\core\utils\ExceptionHandler.o src\build\core\utils\FileDialog.o src\build\core\utils\input.o src\build\core\utils\Logging.o src\build\core\utils\Profiler.o src\build\core\utils\Texture.o src\build\core\utils\utils.o src\build\editor\windows\AssetBrowser.o src\build\editor\windows\Inspector.o src\build\Entitys\Object.o src\build\utils\GameObjectsList.o src\build\utils\Shader.o src\build\utils\UID.o src\build\lapi.o src\build\lauxlib.o src\build\lbaselib.o src\build\lcode.o src\build\lcorolib.o src\build\lctype.o src\build\ldblib.o src\build\ldebug.o src\build\ldo.o src\build\ldump.o src\build\lfunc.o src\build\lgc.o src\build\linit.o src\build\liolib.o src\build\llex.o src\build\lmathlib.o src\build\lmem.o src\build\loadlib.o src\build\lobject.o src\build\lopcodes.o src\build\loslib.o src\build\lparser.o src\build\lstate.o src\build\lstring.o src\build\lstrlib.o src\build\ltable.o src\build\ltablib.o src\build\ltm.o src\build\lua.o src\build\luac.o src\build\lundump.o src\build\lutf8lib.o src\build\lvm.o src\build\lzio.o src\build\imgui.o src\build\imgui_demo.o src\build\imgui_draw.o src\build\imgui_impl_glfw.o src\build\imgui_impl_opengl3.o src\build\imgui_tables.o src\build\imgui_widgets.o src\build\aabb.o src\build\arena_allocator.o src\build\array.o src\build\bitset.o src\build\body.o src\build\broad_phase.o src\build\constraint_graph.o src\build\contact.o src\build\contact_solver.o src\build\core.o src\build\distance.o src\build\distance_joint.o src\build\dynamic_tree.o src\build\geometry.o src\build\hull.o src\build\id_pool.o src\build\island.o src\build\joint.o src\build\manifold.o src\build\math_functions.o src\build\motor_joint.o src\build\mouse_joint.o src\build\mover.o src\build\prismatic_joint.o src\build\revolute_joint.o src\build\sensor.o src\build\shape.o src\build\solver.o src\build\solver_set.o src\build\table.o src\build\timer.o src\build\types.o src\build\weld_joint.o src\build\wheel_joint.o src\build\world.o -o src\build\app.exe -LC:\msys64\mingw64\lib -lglfw3 -lglew32 -lopengl32 -lgdi32 -lyaml-cpp -lcomdlg32 -lssl -lcrypto
[RUN] Executed app.exe successfully.
[LINK] g++ src\build\Engine.o src\build\main.o src\build\Renderer.o src\build\Components\AnimationComponent.o src\build\Components\CameraComponent.o src\build\Components\LightComponent.o src\build\Components\ParticleComponent.o src\build\Components\PhysicsComponent.o src\build\Components\ScriptComponent.o src\build\Components\SpriteComponent.o src\build\Components\TextComonent.o src\build\Components\TilemapComponent.o src\build\core\utils\AssetManager.o src\build\core\utils\EngineConfig.o src\build\core\utils\ExceptionHandler.o src\build\core\utils\FileDialog.o src\build\core\utils\input.o src\build\core\utils\Logging.o src\build\core\utils\Profiler.o src\build\core\utils\Texture.o src\build\core\utils\utils.o src\build\editor\windows\AssetBrowser.o src\build\editor\windows\Inspector.o src\build\Entitys\Object.o src\build\utils\GameObjectsList.o src\build\utils\Shader.o src\build\utils\UID.o src\build\lapi.o src\build\lauxlib.o src\build\lbaselib.o src\build\lcode.o src\build\lcorolib.o src\build\lctype.o src\build\ldblib.o src\build\ldebug.o src\build\ldo.o src\build\ldump.o src\build\lfunc.o src\build\lgc.o src\build\linit.o src\build\liolib.o src\build\llex.o src\build\lmathlib.o src\build\lmem.o src\build\loadlib.o src\build\lobject.o src\build\lopcodes.o src\build\loslib.o src\build\lparser.o src\build\lstate.o src\build\lstring.o src\build\lstrlib.o src\build\ltable.o src\build\ltablib.o src\build\ltm.o src\build\lua.o src\build\luac.o src\build\lundump.o src\build\lutf8lib.o src\build\lvm.o src\build\lzio.o src\build\imgui.o src\build\imgui_demo.o src\build\imgui_draw.o src\build\imgui_impl_glfw.o src\build\imgui_impl_opengl3.o src\build\imgui_tables.o src\build\imgui_widgets.o src\build\aabb.o src\build\arena_allocator.o src\build\array.o src\build\bitset.o src\build\body.o src\build\broad_phase.o src\build\constraint_graph.o src\build\contact.o src\build\contact_solver.o src\build\core.o src\build\distance.o src\build\distance_joint.o src\build\dynamic_tree.o src\build\geometry.o src\build\hull.o src\build\id_pool.o src\build\island.o src\build\joint.o src\build\manifold.o src\build\math_functions.o src\build\motor_joint.o src\build\mouse_joint.o src\build\mover.o src\build\prismatic_joint.o src\build\revolute_joint.o src\build\sensor.o src\build\shape.o src\build\solver.o src\build\solver_set.o src\build\table.o src\build\timer.o src\build\types.o src\build\weld_joint.o src\build\wheel_joint.o src\build\world.o -o src\build\app.exe -LC:\msys64\mingw64\lib -lglfw3 -lglew32 -lopengl32 -lgdi32 -lyaml-cpp -lcomdlg32 -lssl -lcrypto
[ERROR] Runtime crash
Command 'src\build\app.exe' returned non-zero exit status 3221225477.

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

View File

@ -1,12 +1,12 @@
engine_version: 0.1.0
scene_name: lighting_test_2
scene_hash: 8d1aa1b7b386c5e68c5ad14aa2db10dad6c1fef078b7cbd009df408784b8f915
scene_hash: fd4d1e65a004b05f9654d657efa90617ff63d3c6c4e624518825d4dae50ef3a3
format_version: 1
objects:
- name: Tiles
uid: f5e01f7892874a67b662633650b41dbd
id: 3
position: [0, 0]
position: [426, 1088]
rotation: 0
layer: 0
visable: true
@ -21,86 +21,47 @@ objects:
visable: true
components:
- type: SpriteComponent
texture: C:\Users\spenc\OneDrive\Pictures\textures\bark_willow_02_diff_1k.png
normalMap: C:\Users\spenc\OneDrive\Pictures\textures\bark_willow_02_nor_gl_1k.png
texture: 1
normalMap: 2
renderType: Lit
children: []
- name: Planks
uid: 13d8988343354e3c8a1f51c03ed40cda
id: 5
position: [1024, 0]
position: [2048, 0]
rotation: 0
layer: 0
visable: true
components:
- type: SpriteComponent
texture: C:\Users\spenc\OneDrive\Pictures\textures\wood_floor_worn_diff_1k.png
normalMap: C:\Users\spenc\OneDrive\Pictures\textures\wood_floor_worn_nor_gl_1k.png
texture: 3
normalMap: 4
renderType: Lit
children: []
- name: Rocks
uid: cff28abe7e3b455ab9b756acc84cd2d7
id: 6
position: [0, 1024]
position: [0, 2048]
rotation: 0
layer: 0
visable: true
components:
- type: SpriteComponent
texture: C:\Users\spenc\OneDrive\Pictures\textures\ganges_river_pebbles_diff_1k.png
normalMap: C:\Users\spenc\OneDrive\Pictures\textures\ganges_river_pebbles_nor_gl_1k.png
texture: 6
normalMap: 5
renderType: Lit
children: []
- name: Metal
uid: 98967eb30e5b429b992766d8062b7c17
id: 7
position: [1024, 1024]
position: [2048, 2048]
rotation: 0
layer: 0
visable: true
components:
- type: SpriteComponent
texture: C:\Users\spenc\OneDrive\Pictures\textures\metal_plate_diff_1k.png
normalMap: C:\Users\spenc\OneDrive\Pictures\textures\metal_plate_nor_gl_1k.png
renderType: Lit
children: []
- name: Logo
uid: c4ce6f16dfb347b0ae0ac67f5881b243
id: 8
position: [3181, 56]
rotation: 0
layer: 0
visable: true
components:
- type: SpriteComponent
texture: C:\Users\spenc\OneDrive\Pictures\blue_logo.png
normalMap: C:\Users\spenc\OneDrive\Pictures\textures\circuits_normal.jpg
renderType: Lit
children: []
- name: Carbooon Fobar
uid: 5ea269572751401da6d86519d3513b7d
id: 9
position: [4087.8999, 3070]
rotation: 0
layer: 1
visable: true
components:
- type: SpriteComponent
texture: C:\Users\spenc\OneDrive\Pictures\textures\carbon-fiber-smooth-bl\carbon-fiber-smooth-bl\carbon-fiber_smooth_albedo.png
normalMap: C:\Users\spenc\OneDrive\Pictures\textures\carbon-fiber-smooth-bl\carbon-fiber-smooth-bl\carbon-fiber_smooth_normal-ogl.png
renderType: Lit
children: []
- name: Carbooon Fobar 2
uid: a36b71937ba349bd8e6414f75be9ee16
id: 10
position: [-7.69999981, 3070]
rotation: 0
layer: 0
visable: true
components:
- type: SpriteComponent
texture: C:\Users\spenc\OneDrive\Pictures\textures\carbon-fiber-smooth-bl\carbon-fiber-smooth-bl\carbon-fiber_smooth_albedo.png
normalMap: C:\Users\spenc\OneDrive\Pictures\textures\carbon-fiber-smooth-bl\carbon-fiber-smooth-bl\carbon-fiber_smooth_normal-ogl.png
texture: 7
normalMap: 8
renderType: Lit
children: []
- name: Lights
@ -115,7 +76,7 @@ objects:
- name: Red
uid: 6afde2dd47aa4557b6afb1a607c99dc8
id: 13
position: [574.239258, 805.561768]
position: [1062.8678, 525.513]
rotation: 0
layer: 2
visable: true
@ -133,7 +94,7 @@ objects:
- name: Green
uid: 0f950d76d24b4dc18f54cab2c3aaaf9a
id: 14
position: [1438.05347, 743.714905]
position: [1436.26843, 1306.90405]
rotation: 0
layer: 2
visable: true
@ -151,7 +112,7 @@ objects:
- name: Blue
uid: 09f722f51c7c4b0f98de3a0a16d127c4
id: 15
position: [1059.70728, 1522.72339]
position: [572.863647, 1239.58301]
rotation: 0
layer: 2
visable: true
@ -232,6 +193,7 @@ objects:
endColor: [0.792156875, 0, 1, 1]
loop: true
burst: false
roundness: 1
children: []
- name: Rain
uid: 19253834f75d4e69a618c45ddb14e8b0
@ -256,6 +218,7 @@ objects:
endColor: [0, 0, 1, 0]
loop: true
burst: false
roundness: 1
children: []
- name: Fire
uid: 995af3d194694309a490504eaee3ae92
@ -280,11 +243,61 @@ objects:
endColor: [1, 0, 0, 0]
loop: true
burst: false
roundness: 1
children: []
color_correction:
brightness: 2
saturation: 2
gamma: 1.05999994
bloom: true
intensity: 1.40999997
threshold: 0.300000012
intensity: 0.200000003
threshold: 1.75999999
Assets:
- uaid: 1
path: C:\Users\spenc\OneDrive\Pictures\textures\bark_willow_02_diff_1k.png
filename: bark_willow_02_diff_1k.png
filetype: png
type: 0
size: [1024, 1024]
- uaid: 2
path: C:\Users\spenc\OneDrive\Pictures\textures\bark_willow_02_nor_gl_1k.png
filename: bark_willow_02_nor_gl_1k.png
filetype: png
type: 0
size: [1024, 1024]
- uaid: 3
path: C:\Users\spenc\OneDrive\Pictures\textures\wood_floor_worn_diff_1k.png
filename: wood_floor_worn_diff_1k.png
filetype: png
type: 0
size: [1024, 1024]
- uaid: 4
path: C:\Users\spenc\OneDrive\Pictures\textures\wood_floor_worn_nor_gl_1k.png
filename: wood_floor_worn_nor_gl_1k.png
filetype: png
type: 0
size: [1024, 1024]
- uaid: 5
path: C:\Users\spenc\OneDrive\Pictures\textures\ganges_river_pebbles_nor_gl_1k.png
filename: ganges_river_pebbles_nor_gl_1k.png
filetype: png
type: 0
size: [1024, 1024]
- uaid: 6
path: C:\Users\spenc\OneDrive\Pictures\textures\ganges_river_pebbles_diff_1k.png
filename: ganges_river_pebbles_diff_1k.png
filetype: png
type: 0
size: [1024, 1024]
- uaid: 7
path: C:\Users\spenc\OneDrive\Pictures\textures\metal_plate_diff_1k.png
filename: metal_plate_diff_1k.png
filetype: png
type: 0
size: [1024, 1024]
- uaid: 8
path: C:\Users\spenc\OneDrive\Pictures\textures\metal_plate_nor_gl_1k.png
filename: metal_plate_nor_gl_1k.png
filetype: png
type: 0
size: [1024, 1024]

View File

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

View File

@ -1,15 +1,21 @@
#version 330 core
in vec2 vUV;
out vec4 FragColor;
uniform sampler2D uTex;
uniform vec2 uUVMin;
uniform vec2 uUVMax;
void main()
{
// Rotate UV 90 degrees to the right: (x, y) → (y, 1 - x)
vec2 rotatedUV = vec2(vUV.y, 1.0 - vUV.x);
vec4 color = texture(uTex, rotatedUV);
// Interpolate UVs within atlas range
vec2 uv = mix(uUVMin, uUVMax, rotatedUV);
vec4 color = texture(uTex, uv);
if (color.a < 0.01)
discard;

View File

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

View File

@ -1,11 +1,23 @@
#version 330 core
in vec4 vColor;
in vec2 vUV;
in float vRoundness;
out vec4 FragColor;
void main() {
// Optional: kill particles with near-zero alpha (optional)
if (vColor.a < 0.01)
void main()
{
vec2 pos = vUV * 2.0 - 1.0;
vec2 absPos = abs(pos);
bool insideSquare = all(lessThanEqual(absPos, vec2(1.0)));
bool insideCircle = length(pos) <= 1.0;
bool inside = mix(float(insideSquare), float(insideCircle), vRoundness) >= 0.5;
if (!inside)
discard;
FragColor = vColor;

View File

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

View File

@ -1,71 +1,117 @@
#include "AnimationComponent.h"
AnimationComponent::AnimationComponent(Object* owner)
AnimationComponent::AnimationComponent(Object *owner)
: Component(owner) {}
void AnimationComponent::SetTextureAtlas(const std::string& path, int cols, int rows, float duration) {
texturePath = path;
texture = std::make_shared<Texture>(path);
atlas = TextureAtlas(texture, cols, rows);
columns = cols;
rows = rows;
totalFrames = cols * rows;
frameDuration = duration;
void AnimationComponent::SetTextureAtlasPath(const std::string &path, int texelWidth, int texelHeight, float duration, int start, int end)
{
AssetManager::LoadAssetAsync(path, AssetType::Image);
const auto *asset = AssetManager::GetAssetByPath(path);
if (asset)
SetTextureAtlas(asset->uaid, texelWidth, texelHeight, duration, start, end);
}
void AnimationComponent::SetTextureAtlas(uint64_t uaid, int texelWidth, int texelHeight, float duration, int /*start*/, int /*end*/)
{
textureUAID = uaid;
const auto *asset = AssetManager::GetAssetByID(uaid);
if (!asset || !asset->loaded)
{
Logger::LogError("SetTextureAtlas: Asset not found or not loaded (UAID: %llu)", uaid);
return;
}
int texWidth = static_cast<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::Stop() { playing = false; }
void AnimationComponent::SetLooping(bool l) { loop = l; }
void AnimationComponent::SetSpeed(float s) { speed = s; }
void AnimationComponent::SetFrame(int f) { currentFrame = f % totalFrames; }
void AnimationComponent::SetFrame(int f) { currentFrame = std::clamp(f, startFrame, endFrame); }
void AnimationComponent::Update(float dt) {
if (!playing || totalFrames <= 1) return;
void AnimationComponent::Update(float dt)
{
if (!playing || totalFrames <= 1)
return;
time += dt * speed;
if (time >= frameDuration) {
if (time >= frameDuration)
{
time -= frameDuration;
currentFrame++;
if (currentFrame >= totalFrames) {
if (currentFrame > endFrame)
{
if (loop)
currentFrame = 0;
else {
currentFrame = totalFrames - 1;
currentFrame = startFrame;
else
{
currentFrame = endFrame;
playing = false;
}
}
}
}
std::string AnimationComponent::GetName() const { return "AnimationComponent"; }
std::string AnimationComponent::GetName() const {
return "AnimationComponent";
}
void AnimationComponent::Save(YAML::Emitter& out) const {
void AnimationComponent::Save(YAML::Emitter &out) const
{
out << YAML::Key << "AnimationComponent";
out << YAML::BeginMap;
out << YAML::Key << "TexturePath" << YAML::Value << texturePath;
out << YAML::Key << "Columns" << YAML::Value << columns;
out << YAML::Key << "Rows" << YAML::Value << rows;
out << YAML::Key << "TextureUAID" << YAML::Value << textureUAID;
out << YAML::Key << "TexelWidth" << YAML::Value << atlas.frameWidth;
out << YAML::Key << "TexelHeight" << YAML::Value << atlas.frameHeight;
out << YAML::Key << "FrameDuration" << YAML::Value << frameDuration;
out << YAML::Key << "StartFrame" << YAML::Value << startFrame;
out << YAML::Key << "EndFrame" << YAML::Value << endFrame;
out << YAML::EndMap;
}
void AnimationComponent::Load(const YAML::Node& node) {
void AnimationComponent::Load(const YAML::Node &node)
{
if (!node["AnimationComponent"])
return;
const auto& data = node["AnimationComponent"];
std::string path = data["TexturePath"].as<std::string>();
int cols = data["Columns"].as<int>();
int rows = data["Rows"].as<int>();
float duration = data["FrameDuration"].as<float>();
const auto &data = node["AnimationComponent"];
uint64_t uaid = data["TextureUAID"].as<uint64_t>();
int texelWidth = data["TexelWidth"].as<int>();
int texelHeight = data["TexelHeight"].as<int>();
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 "../core/utils/Texture.h"
#include "../core/utils/TextureAtlas.h"
#include "../core/utils/AssetManager.h"
#include "../core/utils/Logging.h"
class AnimationComponent : public Component
{
public:
AnimationComponent(Object *owner);
void SetTextureAtlas(const std::string &path, int cols, int rows, float frameDuration);
void SetTextureAtlasPath(const std::string &path, int texelWidth, int texelHeight, float frameDuration, int startFrame = 0, int endFrame = INT_MAX);
void SetTextureAtlas(uint64_t uaid, int texelWidth, int texelHeight, float frameDuration, int startFrame = 0, int endFrame = INT_MAX);
void Play();
void Stop();
@ -25,9 +29,11 @@ public:
float GetSpeed() const { return speed; }
TextureAtlas *GetAtlas() { return &atlas; }
const TextureAtlas *GetAtlas() const { return &atlas; }
int GetCurrentFrame() const { return currentFrame; }
const std::string &GetTexturePath() const { return texturePath; }
uint64_t GetTextureUAID() const { return textureUAID; }
float GetFrameDuration() const { return frameDuration; }
void Update(float dt);
@ -36,9 +42,11 @@ public:
void Save(YAML::Emitter &out) const override;
void Load(const YAML::Node &node) override;
private:
std::string texturePath;
RenderType renderType;
private:
std::shared_ptr<Texture> texture;
TextureAtlas atlas;
@ -46,10 +54,15 @@ private:
int rows = 1;
int totalFrames = 1;
int startFrame = 0;
int endFrame = 0;
float frameDuration = 0.1f;
float time = 0.0f;
int currentFrame = 0;
bool playing = true;
bool loop = true;
float speed = 1.0f;
uint64_t textureUAID = 0;
};

View File

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

View File

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

View File

@ -1,81 +1,12 @@
#include "SpriteComponent.h"
#define STB_IMAGE_IMPLEMENTATION
#include <stb_image.h>
#include <unordered_map>
#include <GL/glew.h>
#include <iostream>
#include "../core/utils/AssetManager.h"
#include "../core/utils/Logging.h"
#include "../core/utils/utils.h"
#include <GL/glew.h>
SpriteComponent::SpriteComponent(Object *owner) : Component(owner) {}
unsigned int SpriteComponent::LoadTexture(const std::string& path, bool updateSize)
{
auto [it, inserted] = textureCache.try_emplace(path, ImageCacheEntry{});
if (!inserted)
{
if (updateSize)
size = it->second.size;
Logger::LogDebug("Using Cached Image: '%s', Texture ID: %u", path.c_str(), it->second.textureID);
return it->second.textureID;
}
int w, h, channels;
stbi_set_flip_vertically_on_load(false);
unsigned char* data = stbi_load(path.c_str(), &w, &h, &channels, 4);
if (!data)
{
Logger::LogError("Failed to load image: '%s': %s", path.c_str(), stbi_failure_reason());
textureCache.erase(it);
return 0;
}
glm::vec2 imageSize(w, h);
if (updateSize)
size = imageSize;
unsigned int id;
glGenTextures(1, &id);
glBindTexture(GL_TEXTURE_2D, id);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, data);
glGenerateMipmap(GL_TEXTURE_2D);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
stbi_image_free(data);
it->second = { id, imageSize };
Logger::LogDebug("Loaded Image: '%s' (%dx%d), Texture ID: %u", path.c_str(), w, h, id);
return id;
}
bool SpriteComponent::HasTexture()
{
return texture_loaded;
@ -83,22 +14,44 @@ bool SpriteComponent::HasTexture()
void SpriteComponent::SetTexture(const std::string &path)
{
if (path.empty())
return;
texturePath = path;
textureID = LoadTexture(path, true);
if (textureID != 0)
{
texture_loaded = true;
}
if (path.empty()) return;
AssetManager::LoadAssetAsync(path, AssetType::Image);
const auto* asset = AssetManager::GetAssetByPath(path);
if (asset)
SetTexture(asset->uaid);
}
void SpriteComponent::SetNormalMap(const std::string &path)
{
if (path.empty())
return;
normalMapPath = path;
normalMapID = LoadTexture(path, false);
if (path.empty()) return;
AssetManager::LoadAssetAsync(path, AssetType::Image);
const auto* asset = AssetManager::GetAssetByPath(path);
if (asset)
SetNormalMap(asset->uaid);
}
void SpriteComponent::SetTexture(uint64_t uaid)
{
textureUAID = uaid;
const auto* asset = AssetManager::GetAssetByID(uaid);
if (asset && asset->loaded)
{
textureID = asset->textureID;
size = asset->size;
texture_loaded = true;
}
}
void SpriteComponent::SetNormalMap(uint64_t uaid)
{
normalMapUAID = uaid;
const auto* asset = AssetManager::GetAssetByID(uaid);
if (asset && asset->loaded)
{
normalMapID = asset->textureID;
}
}
unsigned int SpriteComponent::GetTextureID() const
@ -111,62 +64,42 @@ unsigned int SpriteComponent::GetNormalMapID() const
return normalMapID;
}
std::string SpriteComponent::GetTexturePath() const
uint64_t SpriteComponent::GetTextureUAID() const
{
return texturePath;
return textureUAID;
}
std::string SpriteComponent::GetNormalMapPath() const
uint64_t SpriteComponent::GetNormalMapUAID() const
{
return normalMapPath;
return normalMapUAID;
}
void SpriteComponent::Save(YAML::Emitter &out) const
{
out << YAML::BeginMap;
out << YAML::Key << "type" << YAML::Value << "SpriteComponent";
out << YAML::Key << "texture" << YAML::Value << texturePath;
out << YAML::Key << "normalMap" << YAML::Value << normalMapPath;
out << YAML::Key << "texture" << YAML::Value << textureUAID;
out << YAML::Key << "normalMap" << YAML::Value << normalMapUAID;
out << YAML::Key << "renderType" << YAML::Value << (renderType == RenderType::Lit ? "Lit" : "Unlit");
out << YAML::EndMap;
}
void SpriteComponent::Load(const YAML::Node& node)
{
try {
if (!node["texture"])
{
RecoverableError("Missing 'texture' key in SpriteComponent YAML node", Create::Exceptions::MissingField).Handle();
}
else if (!node["texture"].IsScalar())
{
RecoverableError("'texture' field must be a string", Create::Exceptions::InvalidFormat).Handle();
}
else if (!node["texture"].as<std::string>().empty())
{
SetTexture(node["texture"].as<std::string>());
}
if (node["texture"])
SetTexture(node["texture"].as<uint64_t>());
if (!node["normalMap"])
{
RecoverableError("Missing 'normalMap' key in SpriteComponent YAML node", Create::Exceptions::MissingField).Handle();
}
else if (!node["normalMap"].IsScalar())
{
RecoverableError("'normalMap' field must be a string", Create::Exceptions::InvalidFormat).Handle();
}
else if (!node["normalMap"].as<std::string>().empty())
{
SetNormalMap(node["normalMap"].as<std::string>());
}
if (node["normalMap"])
SetNormalMap(node["normalMap"].as<uint64_t>());
if (node["renderType"] && node["renderType"].IsScalar()) {
std::string typeStr = node["renderType"].as<std::string>();
if (typeStr == "Lit") renderType = RenderType::Lit;
else if (typeStr == "Unlit") renderType = RenderType::Unlit;
else
RecoverableError("Invalid 'renderType' value in SpriteComponent: " + typeStr, Create::Exceptions::InvalidFormat).Handle();
RecoverableError("Invalid 'renderType' value in SpriteComponent: " + typeStr,
Create::Exceptions::InvalidFormat).Handle();
}
} catch (const YAML::Exception& e) {

View File

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

View File

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

View File

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

View File

@ -77,15 +77,16 @@ struct BatchedSprite
glm::vec4 texCoords;
GLuint textureID;
GLuint normalMapID;
SpriteComponent::RenderType renderType;
RenderType renderType;
SpriteComponent *sprite;
};
struct SortedDrawEntry
{
BatchedSprite sprite;
Shader *shader;
bool useLighting;
Shader *shader = nullptr;
bool useLighting = true;
bool usesUV = false;
};
std::vector<CachedLightUniforms> s_LightUniforms;
@ -162,25 +163,26 @@ void Renderer::InitQuadBatch()
std::size_t offset = 0;
glEnableVertexAttribArray(1); // pos
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, sizeof(QuadInstance), (void *)(offset));
glEnableVertexAttribArray(1);
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, sizeof(QuadInstance), (void *)offsetof(QuadInstance, screenPos));
glVertexAttribDivisor(1, 1);
offset += sizeof(glm::vec2);
glEnableVertexAttribArray(2); // size
glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, sizeof(QuadInstance), (void *)(offset));
glEnableVertexAttribArray(2);
glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, sizeof(QuadInstance), (void *)offsetof(QuadInstance, size));
glVertexAttribDivisor(2, 1);
offset += sizeof(glm::vec2);
glEnableVertexAttribArray(3); // rotation
glVertexAttribPointer(3, 1, GL_FLOAT, GL_FALSE, sizeof(QuadInstance), (void *)(offset));
glEnableVertexAttribArray(3);
glVertexAttribPointer(3, 1, GL_FLOAT, GL_FALSE, sizeof(QuadInstance), (void *)offsetof(QuadInstance, rotation));
glVertexAttribDivisor(3, 1);
offset += sizeof(float);
glEnableVertexAttribArray(4); // color
glVertexAttribPointer(4, 4, GL_FLOAT, GL_FALSE, sizeof(QuadInstance), (void *)(offset));
glEnableVertexAttribArray(4);
glVertexAttribPointer(4, 4, GL_FLOAT, GL_FALSE, sizeof(QuadInstance), (void *)offsetof(QuadInstance, color));
glVertexAttribDivisor(4, 1);
glEnableVertexAttribArray(5);
glVertexAttribPointer(5, 1, GL_FLOAT, GL_FALSE, sizeof(QuadInstance), (void *)offsetof(QuadInstance, roundness));
glVertexAttribDivisor(5, 1);
glBindVertexArray(0);
}
@ -525,7 +527,14 @@ void Renderer::DrawQuad(const core::types::Vec2 &pos, const core::types::Vec2 &s
s_QuadBatch.push_back({pos, size, rotation, color});
}
void Renderer::BatchQuad(const core::types::Vec2 &worldPos, const core::types::Vec2 &size, float rotation, const core::types::Color &color, const core::types::Vec2 &cameraPos, float zoom)
void Renderer::BatchQuad(const core::types::Vec2 &worldPos,
const core::types::Vec2 &size,
float rotation,
const core::types::Color &color,
const core::types::Vec2 &cameraPos,
float zoom,
float isCircle)
{
if (s_QuadBatch.size() >= MAX_QUADS)
FlushQuads();
@ -533,7 +542,16 @@ void Renderer::BatchQuad(const core::types::Vec2 &worldPos, const core::types::V
core::types::Vec2 screenPos = (worldPos - cameraPos) * zoom + core::types::Vec2(width * 0.5f, height * 0.5f);
core::types::Vec2 finalSize = size * zoom;
s_QuadBatch.push_back({screenPos, finalSize, rotation, color});
s_QuadBatch.push_back({screenPos, finalSize, rotation, color, isCircle});
}
void Renderer::BatchCircle(const core::types::Vec2 &worldPos,
const core::types::Vec2 &size,
const core::types::Color &color,
const core::types::Vec2 &cameraPos,
float zoom)
{
BatchQuad(worldPos, size, 0.0f, color, cameraPos, zoom, 1.0f);
}
void Renderer::DrawSprite(SpriteComponent *sprite, const glm::vec2 &pos, float zoom, glm::vec2 &CameraPos)
@ -558,7 +576,7 @@ void Renderer::DrawSprite(SpriteComponent *sprite, const glm::vec2 &pos, float z
SortedDrawEntry drawEntry;
drawEntry.sprite = entry;
drawEntry.shader = (g_engineConfig.settings.lighting_enabled && entry.renderType == SpriteComponent::RenderType::Lit)
drawEntry.shader = (g_engineConfig.settings.lighting_enabled && entry.renderType == RenderType::Lit)
? &spriteShader
: &unlitShader;
drawEntry.useLighting = (drawEntry.shader == &spriteShader);
@ -566,7 +584,6 @@ void Renderer::DrawSprite(SpriteComponent *sprite, const glm::vec2 &pos, float z
sortedDrawList.push_back(drawEntry);
}
void Renderer::DrawTextureAtlas(const TextureAtlas *atlas, int index, const core::types::Vec2 &pos, float rotationDeg, float zoom)
{
PROFILE_DEEP_SCOPE("DrawTextureAtlas");
@ -579,7 +596,10 @@ void Renderer::DrawTextureAtlas(const TextureAtlas *atlas, int index, const core
const core::types::Vec2 uvMax = uvMin + atlas->GetFrameSizeUV();
glm::vec2 screenPos = pos * zoom + glm::vec2(width, height) * 0.5f;
glm::vec2 finalSize = glm::vec2(1.0f) * zoom;
glm::vec2 frameSize = atlas->GetFrameSizeUV() * tex->GetSize();
glm::vec2 finalSize = frameSize * zoom;
BatchedSprite entry;
entry.screenPos = screenPos;
@ -587,7 +607,7 @@ void Renderer::DrawTextureAtlas(const TextureAtlas *atlas, int index, const core
entry.rotationRad = glm::radians(rotationDeg);
entry.textureID = tex->GetID();
entry.normalMapID = defaultNormalMap;
entry.renderType = SpriteComponent::RenderType::Unlit; // no lighting for raw atlas drawing
entry.renderType = RenderType::Lit;
entry.sprite = nullptr;
entry.texCoords = glm::vec4(uvMin.x, uvMin.y, uvMax.x, uvMax.y);
@ -595,10 +615,51 @@ void Renderer::DrawTextureAtlas(const TextureAtlas *atlas, int index, const core
drawEntry.sprite = entry;
drawEntry.shader = &unlitShader;
drawEntry.useLighting = false;
drawEntry.usesUV = true; // <- Important!
sortedDrawList.push_back(drawEntry);
}
void Renderer::DrawAnimator(const AnimationComponent *anim, const core::types::Vec2 &worldPos, float zoom, const core::types::Vec2 &cameraPos)
{
PROFILE_DEEP_SCOPE("Renderer::DrawAnimator");
if (!anim || !anim->GetAtlas() || !anim->GetAtlas()->texture)
return;
const TextureAtlas *atlas = anim->GetAtlas();
int frameIndex = anim->GetCurrentFrame();
if (frameIndex >= atlas->GetTotalFrames())
return;
const auto &tex = atlas->texture;
core::types::Vec2 uvMin = atlas->GetFrameUV(frameIndex);
core::types::Vec2 uvMax = uvMin + atlas->GetFrameSizeUV();
core::types::Vec2 texSize = tex->GetSize();
glm::vec2 screenPos = (worldPos - cameraPos) * zoom + glm::vec2(width, height) * 0.5f;
glm::vec2 frameSize = atlas->GetFrameSizeUV() * texSize;
glm::vec2 finalSize = frameSize * zoom;
BatchedSprite entry;
entry.screenPos = screenPos;
entry.size = finalSize;
entry.rotationRad = 0.0f;
entry.textureID = tex->GetID();
entry.normalMapID = defaultNormalMap;
entry.renderType = anim->renderType;
entry.sprite = nullptr;
entry.texCoords = glm::vec4(uvMin.x, uvMin.y, uvMax.x, uvMax.y);
SortedDrawEntry drawEntry;
drawEntry.sprite = entry;
drawEntry.shader = &unlitShader;
drawEntry.useLighting = false;
drawEntry.usesUV = true;
sortedDrawList.push_back(drawEntry);
}
void Renderer::FlushQuads()
{
PROFILE_ENGINE_SCOPE("Renderer::FlushQuads");
@ -614,16 +675,8 @@ void Renderer::FlushQuads()
glBindVertexArray(s_QuadVAO);
glBindBuffer(GL_ARRAY_BUFFER, s_QuadInstanceVBO);
{
PROFILE_DEEP_SCOPE("Upload");
s_UnlitQuadShader.Use();
s_UnlitQuadShader.SetVec2("uScreen", glm::vec2(width, height));
glBindVertexArray(s_QuadVAO);
// Write directly to mapped buffer
std::memcpy(s_QuadMappedPtr, s_QuadBatch.data(), s_QuadBatch.size() * sizeof(QuadInstance));
}
std::memcpy(s_QuadMappedPtr, s_QuadBatch.data(), s_QuadBatch.size() * sizeof(QuadInstance));
}
{
@ -685,13 +738,26 @@ void Renderer::FlushSprites()
}
}
// Uniforms
// Common uniforms
currentShader->SetVec2("uPos", entry.sprite.screenPos);
currentShader->SetVec2("uSize", entry.sprite.size);
currentShader->SetFloat("uRotation", entry.sprite.rotationRad);
currentShader->SetInt("uTex", 0);
// Textures
// Set UVs if applicable
if (entry.usesUV)
{
currentShader->SetVec2("uUVMin", glm::vec2(entry.sprite.texCoords.x, entry.sprite.texCoords.y));
currentShader->SetVec2("uUVMax", glm::vec2(entry.sprite.texCoords.z, entry.sprite.texCoords.w));
}
else
{
// Full UV range fallback
currentShader->SetVec2("uUVMin", glm::vec2(0.0f));
currentShader->SetVec2("uUVMax", glm::vec2(1.0f));
}
// Bind textures
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, entry.sprite.textureID);

View File

@ -6,6 +6,9 @@
#include "Components/TilemapComponent.h"
#include "Components/SpriteComponent.h"
#include "Components/SpriteComponent.h"
#include "Components/AnimationComponent.h"
#include "core/utils/EngineConfig.h"
#include "utils/Shader.h"
#include "core/utils/Profiler.h"
@ -20,7 +23,7 @@ struct ColorCorrection
float gamma = 1.0f;
bool bloom = true;
float threshold = 0.2f;
float threshold = 1.0f;
float intensity = 1.2f;
void Upload(Shader &shader) const
@ -41,10 +44,11 @@ struct Light
struct QuadInstance
{
core::types::Vec2 pos;
core::types::Vec2 screenPos;
core::types::Vec2 size;
float rotation;
core::types::Color color;
float roundness = 0.0f;
};
class Renderer
@ -80,10 +84,24 @@ public:
static void InitQuadBatch();
static void DrawQuad(const core::types::Vec2 &pos, const core::types::Vec2 &size, float rotation, const core::types::Color &color);
static void BatchQuad(const core::types::Vec2 &worldPos, const core::types::Vec2 &size, float rotation, const core::types::Color &color, const core::types::Vec2 &cameraPos, float zoom);
static void BatchQuad(const core::types::Vec2 &worldPos,
const core::types::Vec2 &size,
float rotation,
const core::types::Color &color,
const core::types::Vec2 &cameraPos,
float zoom,
float isCircle = 0.0f);
static void BatchCircle(const core::types::Vec2 &worldPos,
const core::types::Vec2 &size,
const core::types::Color &color,
const core::types::Vec2 &cameraPos,
float zoom);
static void DrawTextureAtlas(const TextureAtlas *atlas, int index, const core::types::Vec2 &pos, float rotationDeg, float zoom);
static void DrawAnimator(const AnimationComponent *anim, const core::types::Vec2 &worldPos, float zoom, const core::types::Vec2 &cameraPos);
static void FlushQuads();
private:

View File

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

View File

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

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(show_color_correction_window, bool, false) \
USER_SETTING(show_profiler_window, bool, false) \
USER_SETTING(lighting_enabled, bool, true) \
USER_SETTING(lighting_enabled, bool, false) \
USER_SETTING(profile_deep, bool, false) \
USER_SETTING(show_asset_window, bool, false) \
USER_SETTING(profile_gpu, bool, false)

View File

@ -1,19 +1,41 @@
#include "Texture.h"
#include <GL/glew.h>
#include <stb_image.h>
#include <iostream>
#include "utils.h"
#include "AssetManager.h"
#include "Logging.h"
Texture::Texture(const std::string &path)
{
id = LoadTextureIfNeeded(path);
if (!path.empty())
{
AssetManager::LoadAssetAsync(path, AssetType::Image);
const auto *asset = AssetManager::GetAssetByPath(path);
if (asset && asset->loaded)
{
id = asset->textureID;
size = asset->size;
}
else
{
Logger::LogError("[Texture] Failed to get asset for path: %s", path.c_str());
}
}
}
Texture::~Texture()
Texture::Texture(uint64_t uaid)
{
const auto *asset = AssetManager::GetAssetByID(uaid);
if (asset && asset->loaded)
{
id = asset->textureID;
size = asset->size;
}
else
{
Logger::LogError("[Texture] Failed to get asset for UAID: %llu", uaid);
}
}
Texture::~Texture() {}
unsigned int Texture::GetID() const
{
return id;

View File

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

View File

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

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)
{
auto [it, inserted] = textureCache.try_emplace(path, ImageCacheEntry{});
@ -39,7 +77,8 @@ GLuint LoadTextureIfNeeded(const std::string &path)
it->second = { id, imageSize };
Logger::LogVerbose("Loaded Image: '%s'", path.c_str());
Logger::LogVerbose("Loaded Image: (%d, %d) '%s'",w, h, path.c_str());
return id;
}

View File

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

View File

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

View File

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