From 22d18c953c6f3400ffc4c47f6634ff06dbe5becc Mon Sep 17 00:00:00 2001 From: mrq Date: Sun, 29 May 2022 22:44:00 -0500 Subject: [PATCH] Commit for 2022.05.29 22-44-19.7z --- bin/data/config.json | 28 +-- bin/data/entities/model.json | 5 +- bin/data/scenes/mcdonalds/craeture.json | 16 ++ bin/data/scenes/mcdonalds/door.json | 9 + bin/data/scenes/mcdonalds/loading.json | 32 +++ bin/data/scenes/mcdonalds/marker.json | 24 +++ bin/data/scenes/mcdonalds/mcdonalds.json | 47 +++++ bin/data/scenes/mcdonalds/player.json | 19 ++ bin/data/scenes/mcdonalds/scene.json | 60 ++++++ bin/data/scenes/mcdonalds/scripts/door.lua | 110 ++++++++++ bin/data/scenes/mcdonalds/scripts/realign.lua | 22 ++ bin/data/scenes/mcdonalds/scripts/static.lua | 90 +++++++++ bin/data/scenes/mcdonalds/sound.json | 34 ++++ bin/data/scenes/mcdonalds/static.json | 48 +++++ bin/data/scenes/sh2_mcdonalds/craeture.json | 16 ++ bin/data/scenes/sh2_mcdonalds/door.json | 11 + bin/data/scenes/sh2_mcdonalds/loading.json | 32 +++ bin/data/scenes/sh2_mcdonalds/marker.json | 24 +++ bin/data/scenes/sh2_mcdonalds/player.json | 20 ++ .../scenes/sh2_mcdonalds/playerLight.json | 32 +++ bin/data/scenes/sh2_mcdonalds/prop.json | 11 + bin/data/scenes/sh2_mcdonalds/scene.json | 60 ++++++ .../scenes/sh2_mcdonalds/scripts/door.lua | 107 ++++++++++ .../scenes/sh2_mcdonalds/scripts/realign.lua | 22 ++ .../scenes/sh2_mcdonalds/scripts/static.lua | 90 +++++++++ .../sh2_mcdonalds/scripts/trackPlayer.lua | 11 + .../scenes/sh2_mcdonalds/sh2_mcdonalds.json | 110 ++++++++++ bin/data/scenes/sh2_mcdonalds/sound.json | 34 ++++ bin/data/scenes/sh2_mcdonalds/static.json | 48 +++++ bin/data/scenes/ss2/medsci.json | 37 ++-- bin/data/shaders/common/functions.h | 13 ++ bin/data/shaders/common/lambert.h | 4 +- bin/data/shaders/common/light.h | 9 + bin/data/shaders/common/pbr.h | 14 +- bin/data/shaders/common/structs.h | 1 + bin/data/shaders/common/vxgi.h | 2 +- bin/data/shaders/display/subpass.h | 18 +- bin/data/shaders/display/vxgi.comp.h | 34 ++-- bin/data/shaders/graph/baking/bake.frag.glsl | 58 +++++- engine/inc/uf/engine/asset/asset.h | 2 + engine/inc/uf/engine/entity/entity.h | 6 +- engine/inc/uf/engine/object/behavior.h | 1 + engine/inc/uf/engine/object/object.h | 2 + engine/inc/uf/utils/thread/thread.h | 1 + engine/src/engine/asset/asset.cpp | 37 +++- engine/src/engine/graph/decode.cpp | 4 +- engine/src/engine/graph/encode.cpp | 4 +- engine/src/engine/graph/graph.cpp | 190 ++++++++---------- engine/src/engine/object/object.cpp | 39 +++- engine/src/ext/gltf/gltf.cpp | 25 ++- engine/src/ext/gltf/processPrimitives2.inl | 5 +- engine/src/ext/xatlas/xatlas.cpp | 99 +++++++-- engine/src/ext/xatlas/xatlas_src.cpp | 7 +- engine/src/utils/thread/thread.cpp | 16 +- ext/behaviors/baking/behavior.cpp | 33 ++- ext/behaviors/baking/behavior.h | 4 +- ext/main.cpp | 3 + 57 files changed, 1570 insertions(+), 270 deletions(-) create mode 100644 bin/data/scenes/mcdonalds/craeture.json create mode 100644 bin/data/scenes/mcdonalds/door.json create mode 100644 bin/data/scenes/mcdonalds/loading.json create mode 100644 bin/data/scenes/mcdonalds/marker.json create mode 100644 bin/data/scenes/mcdonalds/mcdonalds.json create mode 100644 bin/data/scenes/mcdonalds/player.json create mode 100644 bin/data/scenes/mcdonalds/scene.json create mode 100644 bin/data/scenes/mcdonalds/scripts/door.lua create mode 100644 bin/data/scenes/mcdonalds/scripts/realign.lua create mode 100644 bin/data/scenes/mcdonalds/scripts/static.lua create mode 100644 bin/data/scenes/mcdonalds/sound.json create mode 100644 bin/data/scenes/mcdonalds/static.json create mode 100644 bin/data/scenes/sh2_mcdonalds/craeture.json create mode 100644 bin/data/scenes/sh2_mcdonalds/door.json create mode 100644 bin/data/scenes/sh2_mcdonalds/loading.json create mode 100644 bin/data/scenes/sh2_mcdonalds/marker.json create mode 100644 bin/data/scenes/sh2_mcdonalds/player.json create mode 100644 bin/data/scenes/sh2_mcdonalds/playerLight.json create mode 100644 bin/data/scenes/sh2_mcdonalds/prop.json create mode 100644 bin/data/scenes/sh2_mcdonalds/scene.json create mode 100644 bin/data/scenes/sh2_mcdonalds/scripts/door.lua create mode 100644 bin/data/scenes/sh2_mcdonalds/scripts/realign.lua create mode 100644 bin/data/scenes/sh2_mcdonalds/scripts/static.lua create mode 100644 bin/data/scenes/sh2_mcdonalds/scripts/trackPlayer.lua create mode 100644 bin/data/scenes/sh2_mcdonalds/sh2_mcdonalds.json create mode 100644 bin/data/scenes/sh2_mcdonalds/sound.json create mode 100644 bin/data/scenes/sh2_mcdonalds/static.json create mode 100644 bin/data/shaders/common/light.h diff --git a/bin/data/config.json b/bin/data/config.json index c88c2200..e9a0848e 100644 --- a/bin/data/config.json +++ b/bin/data/config.json @@ -1,16 +1,16 @@ { "engine": { "scenes": { - "start": "SS2", - "meshes": { "interleave": false }, + "start": "McDonalds", + "meshes": { "interleave": true }, "matrix": { "reverseInfinite": true }, "lights": { - "max": 12, + "max": 16, "enabled": true }, "shadows": { "enabled": true, - "update": 4, + "update": 3, "max": 6, "samples": 2, "experimental mode": 1 @@ -48,18 +48,19 @@ "validation": { "enabled": false, "filters": [ - "MessageID = 0x124ffb34", // VUID-VkImageMemoryBarrier-oldLayout-01197 - "MessageID = 0x8ab1932c", // VUID-VkImageViewCreateInfo-imageViewType-04973 + "MessageID = 0x4dae5635", // UNASSIGNED-CoreValidation-DrawState-InvalidImageLayout (false positive for cubemaps) + "MessageID = 0x609a13b", // UNASSIGNED-CoreValidation-Shader-OutputNotConsumed (from depth-only calls) + "MessageID = 0x23e43bb7" // UNASSIGNED-CoreValidation-Shader-InputNotProduced (from depth-only calls) + + // "MessageID = 0xe91b58a0" // VUID-vkCmdDrawIndexed-None-02686 (?) + // "MessageID = 0x71500fba", // VUID-vkDestroyDevice-device-00378 (don't care about a clean cleanup) + + // "MessageID = 0x124ffb34", // VUID-VkImageMemoryBarrier-oldLayout-01197 (hacky bloom-shit) + // "MessageID = 0x8ab1932c", // VUID-VkImageViewCreateInfo-imageViewType-04973 (hacky bloom-shit) // "MessageID = 0x8e1000ad", // VUID-vkCmdDrawIndexedIndirect-None-04008 (bitches without nullDescriptor) // "MessageID = 0x9dd97212", // VUID-vkCmdDrawIndexedIndirect-None-02721 (bitches without nullDescriptor) // "MessageID = 0x36481fcb", // VUID-vkCmdBindVertexBuffers-pBuffers-04001 (bitches without nullDescriptor) - - "MessageID = 0x4dae5635", // UNASSIGNED-CoreValidation-DrawState-InvalidImageLayout (false positive for cubemaps) - // "MessageID = 0x71500fba", // VUID-vkDestroyDevice-device-00378 (don't care about a clean cleanup) - "MessageID = 0x609a13b", // UNASSIGNED-CoreValidation-Shader-OutputNotConsumed (from depth-only calls) - "MessageID = 0x23e43bb7" // UNASSIGNED-CoreValidation-Shader-InputNotProduced (from depth-only calls) - // "MessageID = 0xe91b58a0" // VUID-vkCmdDrawIndexed-None-02686 (?) ] }, "framebuffer": { @@ -237,6 +238,9 @@ "entity": { "delete children on destroy": true, "delete components on destroy": true + }, + "loader": { + "assert": true } } }, diff --git a/bin/data/entities/model.json b/bin/data/entities/model.json index dd7a6d51..3fe5096c 100644 --- a/bin/data/entities/model.json +++ b/bin/data/entities/model.json @@ -30,10 +30,11 @@ "resolution": 8192, "shadows": 1024, "layers": 1, - "trigger": { "mode": "rendered" }, + "trigger": { "mode": "rendered", "quit": true }, + // "trigger": { "mode": "key", "value": "B" }, "output": "./lightmap.%i.png" }, - "grid": { + "-grid": { "/^worldspawn/": { "size": [6,6,6], // "epsilon": 0.01, diff --git a/bin/data/scenes/mcdonalds/craeture.json b/bin/data/scenes/mcdonalds/craeture.json new file mode 100644 index 00000000..9a3f7b7a --- /dev/null +++ b/bin/data/scenes/mcdonalds/craeture.json @@ -0,0 +1,16 @@ +{ + "name": "Craeture", + "behaviors": [ "CraetureBehavior" ], + "assets": [ + "./textures/craeture.jpg" + ], + "transform": { + "position": [9.62326, 1.1872, -40.8126], + "scale": [8, 8, 8] + }, + "metadata": { + "model": { + "cull mode": "none" + } + } +} \ No newline at end of file diff --git a/bin/data/scenes/mcdonalds/door.json b/bin/data/scenes/mcdonalds/door.json new file mode 100644 index 00000000..41caf066 --- /dev/null +++ b/bin/data/scenes/mcdonalds/door.json @@ -0,0 +1,9 @@ +{ + "assets": ["./scripts/door.lua"], + "system": { + "physics": { + "type": "bounding box", + "recenter": true + } + } +} \ No newline at end of file diff --git a/bin/data/scenes/mcdonalds/loading.json b/bin/data/scenes/mcdonalds/loading.json new file mode 100644 index 00000000..0ec6c59c --- /dev/null +++ b/bin/data/scenes/mcdonalds/loading.json @@ -0,0 +1,32 @@ +{ + "name": "Gui: Loading", + "type": "Object", + "behaviors": [ + // "GuiBehavior" + ], + "assets": [ + { "filename": "./mcdonalds.json", "delay": 0 } + ], + "ignore": false, + "transform": { + "position": [ -0.830591, -0.699509, 0 ], + "rotation": { + "axis": [ 1, 0, 0 ], + "angle": 0 + }, + "scale": [ 0.258737, 0.115371, 1 ] + }, + "metadata": { + "uv": [ 0, 0, 1, 1 ], + "color": [ 1, 1, 1, 0.1 ], + "location": "", + "scaling": "relative", + "text settings": { + "stroke": [ 1, 0.749, 0.368, 1 ], + "color": [ 1, 0.749, 0.368, 1 ], + + "string": "Loading...", + "string1": "コマンド" + } + } +} \ No newline at end of file diff --git a/bin/data/scenes/mcdonalds/marker.json b/bin/data/scenes/mcdonalds/marker.json new file mode 100644 index 00000000..e724cc23 --- /dev/null +++ b/bin/data/scenes/mcdonalds/marker.json @@ -0,0 +1,24 @@ +{ + "name": "Marker", + "type": "Gui", + "ignore": false, + "transform": { + "position": [ 0, 0, 0 ], + "rotation": { + "axis": [ 1, 0, 0 ], + "angle": 0 + }, + "scale": [ 1, 1, 1 ] + }, + "metadata": { + "uv": [ 0, 0, 1, 1 ], + "color": [ 1, 1, 1, 0.8 ], + "location": "", + "scaling": [ 1, 1 ], + "world": true, + "gui layer": false + }, + "assets": [ + "https://cdn..xyz//unity/Android/sprite/sprite_magiccircle_in2.png" + ] +} \ No newline at end of file diff --git a/bin/data/scenes/mcdonalds/mcdonalds.json b/bin/data/scenes/mcdonalds/mcdonalds.json new file mode 100644 index 00000000..c4cc22c7 --- /dev/null +++ b/bin/data/scenes/mcdonalds/mcdonalds.json @@ -0,0 +1,47 @@ +{ + "import": "/model.json", + "assets": [ + // { "filename": "./static.json", "delay": 8 }, + + // { "filename": "./models/mcdonalds.glb", "delay": 0, "single threaded": false } + // { "filename": "./models/mcdonalds/graph.json", "delay": 0, "single threaded": false, "category": "models" } + { "filename": "./models/mcdonalds/graph.json.gz", "delay": 0, "single threaded": false, "category": "models" } + + // { "filename": "./models/mini_mcd.glb", "delay": 0, "single threaded": false } + // { "filename": "./models/mini_mcd/graph.json.gz", "delay": 0, "single threaded": false, "category": "models" } + ], + "metadata": { + "model": { + "lightmap": true, + "baking": { + "enabled": true, + "resolution": 2048 + }, + "cull mode": "none", + "tags": { + "/^worldspawn/": { + "physics": { "type": "mesh", "static": true }, + "grid": { "size": [3,2,3], "epsilon": 1.0, "cleanup": true, "print": true } + }, + "info_player_spawn": { "action": "attach", "filename": "./player.json", "preserve orientation": true }, + + "func_door_rotating_5409": { "action": "load", "payload": { "import": "./door.json", "metadata": { "angle":-1.570795, "normal": [-1,0,0] } } }, + "func_door_rotating_5487": { "action": "load", "payload": { "import": "./door.json", "metadata": { "angle": 1.570795, "normal": [ 1,0,0] } } }, + "func_door_rotating_5495": { "action": "load", "payload": { "import": "./door.json", "metadata": { "angle": 1.570795, "normal": [ 1,0,0] } } }, + "func_door_rotating_5568": { "action": "load", "payload": { "import": "./door.json", "metadata": { "angle":-1.570795, "normal": [-1,0,0] } } }, + "func_door_rotating_5568": { "action": "load", "payload": { "import": "./door.json", "metadata": { "angle":-1.570795, "normal": [-1,0,0] } } }, + "func_door_rotating_5576": { "action": "load", "payload": { "import": "./door.json", "metadata": { "angle":-1.570795, "normal": [-1,0,0] } } }, + "func_door_rotating_5584": { "action": "load", "payload": { "import": "./door.json", "metadata": { "angle":-1.570795, "normal": [-1,0,0] } } }, + "func_door_rotating_5656": { "action": "load", "payload": { "import": "./door.json", "metadata": { "angle": 1.570795, "normal": [ 1,0,0] } } }, + "func_door_rotating_5664": { "action": "load", "payload": { "import": "./door.json", "metadata": { "angle":-1.570795, "normal": [-1,0,0] } } }, + "func_door_rotating_5689": { "action": "load", "payload": { "import": "./door.json", "metadata": { "angle":-1.570795, "normal": [-1,0,0] } } }, + "func_door_rotating_5698": { "action": "load", "payload": { "import": "./door.json", "metadata": { "angle":-1.570795, "normal": [-1,0,0] } } }, + "func_door_rotating_5712": { "action": "load", "payload": { "import": "./door.json", "metadata": { "angle":-1.570795, "normal": [-1,0,0] } } }, + + "func_physbox_5212": { "action": "load", "payload": { "import": "./door.json", "metadata": { "angle":-1.570795, "normal": [-1,0,0] } } }, + "func_physbox_5548": { "action": "load", "payload": { "import": "./door.json", "metadata": { "angle":-1.570795, "normal": [-1,0,0] } } }, + "func_physbox_5931": { "action": "load", "payload": { "import": "./door.json", "metadata": { "angle":-1.570795, "normal": [-1,0,0] } } } + } + } + } +} \ No newline at end of file diff --git a/bin/data/scenes/mcdonalds/player.json b/bin/data/scenes/mcdonalds/player.json new file mode 100644 index 00000000..dec26007 --- /dev/null +++ b/bin/data/scenes/mcdonalds/player.json @@ -0,0 +1,19 @@ +{ + "import": "/player.json", + "assets": [ + // { "filename": "/gui/hud/hud.json", "delay": 0 } + ], + "metadata": { + "overlay": { + "floating": true + }, + "collider": true, + "light": { + "should": false, + "color": [1, 1, 1], + "position": [ 0, 2.5, 0 ], + "power": 1, + "radius": [0.001, 32] + } + } +} \ No newline at end of file diff --git a/bin/data/scenes/mcdonalds/scene.json b/bin/data/scenes/mcdonalds/scene.json new file mode 100644 index 00000000..92463acb --- /dev/null +++ b/bin/data/scenes/mcdonalds/scene.json @@ -0,0 +1,60 @@ +{ + "import": "/scene.json", + "assets": [ + "./audio/soundscape/ambience.ogg", + "./loading.json", + "./static.json" + ], + "system": { + "hot reload": { + "enabled": true + }, + "renderer": { + "shader": { + "mode": 1, + "scalar": 16, + "parameters": [ 0, 0, 0, "time" ] + }, + "clear values": [ + [ 1, 1, 1, 0 ] + ] + } + }, + "metadata": { + "menus": { + "pause": "/gui/pause/menu.json" + }, + "bloom": { + "scale": 6.0, + "strength": 0.125, + "sigma": 0.125, + "samples": 8 + }, + "light": { + "exposure": 1.0, + "gamma": 1.0, + "brightnessThreshold": 1.2, + // "ambient": [ 0.1, 0.1, 0.1 ], + "ambient": [ 0, 0, 0 ], + + "fog-": { + "color": [ 0.5, 0.5, 0.5 ], + "range": [ 16, 32 ], + "step scale": 2, + "absorbtion": 0.07, + "density": { + "threshold": 0.35, + "multiplier": 5.0, + "scale": 25.0, + "offset": [0, -1, 1], + "timescale": 8 + } + }, + "should": true, + "shadows": true + }, + "noise": { + "size": [ 64, 64, 64 ] + } + } +} \ No newline at end of file diff --git a/bin/data/scenes/mcdonalds/scripts/door.lua b/bin/data/scenes/mcdonalds/scripts/door.lua new file mode 100644 index 00000000..ce18d5c1 --- /dev/null +++ b/bin/data/scenes/mcdonalds/scripts/door.lua @@ -0,0 +1,110 @@ +local scene = entities.currentScene() +local controller = entities.controller() + +local timer = Timer.new() +if not timer:running() then + timer:start(); +end + +local polarity = 1 +local state = 0 +local targetAlpha = 1 +local alpha = 0 +local target = Vector3f(0,0,0) +local transform = ent:getComponent("Transform") +local metadata = ent:getComponent("Metadata") +local speed = metadata["speed"] or 1.0 +local normal = Vector3f(0,0,-1) +if metadata["normal"] ~= nil then + local sign = -1 + if metadata["angle"] < 0 then sign = 1 end + normal = Vector3f( metadata["normal"][1] * sign, metadata["normal"][2] * sign, metadata["normal"][3] * sign ):normalize() +end +local starting = Quaternion(transform.orientation) +local ending = transform.orientation:multiply(Quaternion.axisAngle( Vector3f(0,1,0), metadata["angle"] )) +local soundEmitter = ent:loadChild("./sound.json",true) +local playSound = function( key, loop ) + if not loop then loop = false end + local url = "/door/" .. key .. ".ogg" + soundEmitter:queueHook("sound:Emit.%UID%", { + filename = string.resolveURI(url, metadata["system"]["root"]), + spatial = true, + streamed = true, + volume = "sfx", + loop = loop + }, 0) +end +local stopSound = function( key ) + local url = "/door/" .. key .. ".ogg" + soundEmitter:queueHook("sound:Stop.%UID%", { + filename = string.resolveURI(url, metadata["system"]["root"]) + }, 0) +end +local playSoundscape = function( key ) + local url = "/soundscape/" .. key .. ".ogg" + soundEmitter:queueHook("sound:Emit.%UID%", { + filename = string.resolveURI(url, metadata["system"]["root"]), + spatial = false, + volume = "sfx", + loop = true, + streamed = true + }, 0) +end +local stopSoundscape = function( key ) + local url = "/soundscape/" .. key .. ".ogg" + soundEmitter:queueHook("sound:Stop.%UID%", { + filename = string.resolveURI(url, metadata["system"]["root"]) + }, 0) +end +soundEmitter:getComponent("Transform"):setReference( transform ) +-- on tick +ent:bind( "tick", function(self) +-- transform.orientation = starting:slerp( ending, math.cos(time.current() * speed) * 0.5 + 0.5 ) + if state == 1 then + alpha = alpha + time.delta() * speed + + if alpha > targetAlpha then + state = 2 + alpha = targetAlpha + playSound("default_stop") + end + + end + if state == 3 then + alpha = alpha - time.delta() * speed + + if alpha < 0 then + state = 0 + alpha = 0 + playSound("default_stop") + end + end + + if state > 0 then + transform.orientation = starting:slerp( ending, alpha * polarity ) + end +end ) +-- on use +ent:addHook( "entity:Use.%UID%", function( payload ) + if state == 0 then + state = 1 + playSound("default_move") + if payload.uid ~= nil then + local player = entities.get( payload.uid ) + local pTransform = player:getComponent("Transform") + local delta = transform.position - pTransform.position + local side = normal:dot(delta) + if side > 0 then + polarity = 1 + elseif side < 0 then + polarity = -1 + end + end + io.print(ent:name()) + end + if state == 2 then + state = 3 + playSound("default_move") + end + io.print( state, json.encode( payload ) ) +end ) \ No newline at end of file diff --git a/bin/data/scenes/mcdonalds/scripts/realign.lua b/bin/data/scenes/mcdonalds/scripts/realign.lua new file mode 100644 index 00000000..84527d13 --- /dev/null +++ b/bin/data/scenes/mcdonalds/scripts/realign.lua @@ -0,0 +1,22 @@ +local scene = entities.currentScene() +local controller = entities.controller() + +local timer = Timer.new() +if not timer:running() then + timer:start(); +end + +local transform = ent:getComponent("Transform") +-- on tick +ent:bind( "tick", function(self) + local offset = Vector3f(0,0,0) + if window.keyPressed("J") then offset.x = offset.x - time.delta() end + if window.keyPressed("L") then offset.x = offset.x + time.delta() end + if window.keyPressed("N") then offset.y = offset.y - time.delta() end + if window.keyPressed("M") then offset.y = offset.y + time.delta() end + if window.keyPressed("I") then offset.z = offset.z - time.delta() end + if window.keyPressed("K") then offset.z = offset.z + time.delta() end + if offset:magnitude() > 0.0001 then + transform.position = transform.position + offset + end +end ) \ No newline at end of file diff --git a/bin/data/scenes/mcdonalds/scripts/static.lua b/bin/data/scenes/mcdonalds/scripts/static.lua new file mode 100644 index 00000000..085af29f --- /dev/null +++ b/bin/data/scenes/mcdonalds/scripts/static.lua @@ -0,0 +1,90 @@ +local scene = entities.currentScene() +local controller = entities.controller() + +local timer = Timer.new() +if not timer:running() then + timer:start(); +end +-- release control +--[[ +hooks.call("window:Mouse.CursorVisibility", { state = true }) +hooks.call("window:Mouse.Lock", {}); +]] +-- on tick +ent:bind( "tick", function(self) + -- update static effect + local metadatas = { + ent = ent:getComponent("Metadata"), + scene = scene:getComponent("Metadata") + } + local transforms = { + ent = ent:getComponent("Transform"), + controller = controller:getComponent("Transform") + } + local distanceSquared = transforms.controller.position:distance( transforms.ent.position ) + distanceSquared = distanceSquared * distanceSquared + if type(metadatas.ent["static"]["scale"]) == "number" then + distanceSquared = distanceSquared * metadatas.ent["static"]["scale"] + end + local lo = type(metadatas.ent["static"]["range"][1]) == "number" and metadatas.ent["static"]["range"][1] or 0.1 + local hi = type(metadatas.ent["static"]["range"][2]) == "number" and metadatas.ent["static"]["range"][2] or 0.5 + local staticBlend = distanceSquared > 1 and 1.0 / distanceSquared or 1.0 + staticBlend = math.clamp( staticBlend, lo, hi ) + + local flicker = type(metadatas.ent["static"]["flicker"]) == "number" and metadatas.ent["static"]["flicker"] or 0.001 + local pieces = type(metadatas.ent["static"]["pieces"]) == "number" and metadatas.ent["static"]["pieces"] or 1000 + + local payload = { + mode = 2, + parameters = { + [1] = flicker, + [2] = pieces, + [3] = staticBlend, + [4] = "time" + } + } + scene:callHook("shader:Update.%UID%", payload) +end ) + +--[[ +local hud = ent:loadChild("/hud.json", true) +hud:bind( "tick", function(self) + -- update distance HUD element + if timer:elapsed() <= 0.0125 then return end + timer:reset() + + local metadata = self:getComponent("Metadata") + local transforms = { + controller = controller:getComponent("Transform"), + source = ent:getComponent("Transform") + } + local distance = transforms.controller.position:distance( transforms.source.position ) + --distance = string.si( distance, "m" ) + local maximum = 40 + local value = math.floor(distance/maximum * 100) + if value >= 100 then value = 100 end + distance = "Sanity: " .. value .. "%" + --distance = math.floor((15-distance)/15 * 100) .. "%" + if metadata["text settings"]["string"] ~= distance then + self:callHook( "gui:UpdateString.%UID%", { + string = distance + } ) + end +end ) +]] +--[[ +local marker = ent:loadChild("./marker.json", true) +marker:bind( "tick", function(self) + local transform = marker:getComponent("Transform") + local parentTransform = ent:getComponent("Transform") + local controllerTransform = controller:getComponent("Transform") + + local controllerCamera = controller:getComponent("Camera") + local controllerCameraTransform = controllerCamera:getTransform() + + transform.position = parentTransform.position + Vector3f(0,3,0) + transform.orientation = Quaternion.lookAt( transform.position - controllerTransform.position, Vector3f(0,1,0) ) + -- transform.orientation = transform.orientation:normalize() + -- transform.model = controllerCamera:getProjection() * controllerCamera:getView() * Matrix4f.translate( transform.position ) * transform.orientation:matrix() +end ) +]] \ No newline at end of file diff --git a/bin/data/scenes/mcdonalds/sound.json b/bin/data/scenes/mcdonalds/sound.json new file mode 100644 index 00000000..351f92fe --- /dev/null +++ b/bin/data/scenes/mcdonalds/sound.json @@ -0,0 +1,34 @@ +{ + "type": "Object", + "name": "Sound Emitter", + "ignore": false, + "assets": [ + ], + "behaviors": [ + "SoundEmitterBehavior" + ], + "transform": { + "reference": true + }, + "system": { + "hot reload": { + "enabled": true + }, + "defaults": { + "render": true, + "asset load": true + }, + "load": { + "ignore": true + } + }, + "metadata": { + "audio": { + "spatial": true, + "loop": false, + "volume": 1, + "rolloffFactor": 0.5, + "epsilon": 0.5 + } + } +} \ No newline at end of file diff --git a/bin/data/scenes/mcdonalds/static.json b/bin/data/scenes/mcdonalds/static.json new file mode 100644 index 00000000..e02750f9 --- /dev/null +++ b/bin/data/scenes/mcdonalds/static.json @@ -0,0 +1,48 @@ +{ + "type": "Object", + "name": "Static Emitter", + "ignore": false, + "assets": [ + "/overworld/static.ogg", + "./scripts/static.lua" + ], + "behaviors": [ + "SoundEmitterBehavior" + ], + "transform": { + "position": [ -13.4342, 2.43658, 298.797 ], + "rotation": { + "axis": [ 0, 1, 0 ], + "angle": 0 + }, + "scale": [ 1, 1, 1 ] + }, + "system": { + "hot reload": { + "enabled": true + }, + "defaults": { + "render": true, + "asset load": true + }, + "load": { + "ignore": true + } + }, + "metadata": { + "audio": { + "spatial": true, + "loop": true, + "streamed": false, + "volume": 1.6, + "rolloffFactor": 2 + }, + "static": { + "range": [ 0.0025, 1 ], + "flicker": 0.5, + "pieces": 16, + "scale": 0.4 + }, + "distance": false + } +} \ No newline at end of file diff --git a/bin/data/scenes/sh2_mcdonalds/craeture.json b/bin/data/scenes/sh2_mcdonalds/craeture.json new file mode 100644 index 00000000..2987fbf5 --- /dev/null +++ b/bin/data/scenes/sh2_mcdonalds/craeture.json @@ -0,0 +1,16 @@ +{ + "name": "Craeture", + "behaviors": [ "CraetureBehavior" ], + "assets": [ + "./textures/craeture.jpg" + ], + "transform": { + "position": [19.9875, 1.54269, -2.97276], + "scale": [1.5, 2, 1.5] + }, + "metadata": { + "model": { + "cull mode": "none" + } + } +} \ No newline at end of file diff --git a/bin/data/scenes/sh2_mcdonalds/door.json b/bin/data/scenes/sh2_mcdonalds/door.json new file mode 100644 index 00000000..1f268ed9 --- /dev/null +++ b/bin/data/scenes/sh2_mcdonalds/door.json @@ -0,0 +1,11 @@ +{ + "assets": ["./scripts/door.lua"], + "system": { + "physics": { + "mass": 0, + "inertia": [0, 0, 0], + "type": "bounding box", + "recenter": true + } + } +} \ No newline at end of file diff --git a/bin/data/scenes/sh2_mcdonalds/loading.json b/bin/data/scenes/sh2_mcdonalds/loading.json new file mode 100644 index 00000000..de4e9be7 --- /dev/null +++ b/bin/data/scenes/sh2_mcdonalds/loading.json @@ -0,0 +1,32 @@ +{ + "name": "Gui: Loading", + "type": "Object", + "behaviors": [ + // "GuiBehavior" + ], + "assets": [ + { "filename": "./sh2_mcdonalds.json", "delay": 0 } + ], + "ignore": false, + "transform": { + "position": [ -0.830591, -0.699509, 0 ], + "rotation": { + "axis": [ 1, 0, 0 ], + "angle": 0 + }, + "scale": [ 0.258737, 0.115371, 1 ] + }, + "metadata": { + "uv": [ 0, 0, 1, 1 ], + "color": [ 1, 1, 1, 0.1 ], + "location": "", + "scaling": "relative", + "text settings": { + "stroke": [ 1, 0.749, 0.368, 1 ], + "color": [ 1, 0.749, 0.368, 1 ], + + "string": "Loading...", + "string1": "コマンド" + } + } +} \ No newline at end of file diff --git a/bin/data/scenes/sh2_mcdonalds/marker.json b/bin/data/scenes/sh2_mcdonalds/marker.json new file mode 100644 index 00000000..e724cc23 --- /dev/null +++ b/bin/data/scenes/sh2_mcdonalds/marker.json @@ -0,0 +1,24 @@ +{ + "name": "Marker", + "type": "Gui", + "ignore": false, + "transform": { + "position": [ 0, 0, 0 ], + "rotation": { + "axis": [ 1, 0, 0 ], + "angle": 0 + }, + "scale": [ 1, 1, 1 ] + }, + "metadata": { + "uv": [ 0, 0, 1, 1 ], + "color": [ 1, 1, 1, 0.8 ], + "location": "", + "scaling": [ 1, 1 ], + "world": true, + "gui layer": false + }, + "assets": [ + "https://cdn..xyz//unity/Android/sprite/sprite_magiccircle_in2.png" + ] +} \ No newline at end of file diff --git a/bin/data/scenes/sh2_mcdonalds/player.json b/bin/data/scenes/sh2_mcdonalds/player.json new file mode 100644 index 00000000..18145681 --- /dev/null +++ b/bin/data/scenes/sh2_mcdonalds/player.json @@ -0,0 +1,20 @@ +{ + "import": "/player.json", + "assets": [ + // { "filename": "/gui/hud/hud.json", "delay": 0 } + "./playerLight.json" + ], + "metadata": { + "overlay": { + "floating": true + }, + "collider": true, + "light": { + "should": false, + "color": [1, 1, 1], + "position": [ 0, 2.5, 0 ], + "power": 1, + "radius": [0.001, 32] + } + } +} \ No newline at end of file diff --git a/bin/data/scenes/sh2_mcdonalds/playerLight.json b/bin/data/scenes/sh2_mcdonalds/playerLight.json new file mode 100644 index 00000000..573030be --- /dev/null +++ b/bin/data/scenes/sh2_mcdonalds/playerLight.json @@ -0,0 +1,32 @@ +{ + "import": "/light.json", + "ignore": true, + "assets": [ + ], + "transform": { + "track": "parent", + "position": [ 0, 1.7, 0 ] + }, + "system": { + "hot reload": { + "enabled": true + } + }, + "metadata": { + "light": { + "type": "point", + "color": [1, 1, 1], + "power": 15, + "fov": 90, + "bias": { + "constant": 1.25, + "slope": 1.75, + "shader": 0.000005 //0.000000005 + }, + "radius": [0.001, 0], + "resolution": 1024, + "shadows": false, + "static": false + } + } +} \ No newline at end of file diff --git a/bin/data/scenes/sh2_mcdonalds/prop.json b/bin/data/scenes/sh2_mcdonalds/prop.json new file mode 100644 index 00000000..2d33ce82 --- /dev/null +++ b/bin/data/scenes/sh2_mcdonalds/prop.json @@ -0,0 +1,11 @@ +{ + "assets": [], + "system": { + "physics": { + "mass": 0, + "inertia": [0, 0, 0], + "type": "bounding box", + "recenter": true + } + } +} \ No newline at end of file diff --git a/bin/data/scenes/sh2_mcdonalds/scene.json b/bin/data/scenes/sh2_mcdonalds/scene.json new file mode 100644 index 00000000..d81c0d9c --- /dev/null +++ b/bin/data/scenes/sh2_mcdonalds/scene.json @@ -0,0 +1,60 @@ +{ + "import": "/scene.json", + "assets": [ + "./audio/soundscape/ambience.ogg", + "./loading.json" + // "./static.json" + ], + "system": { + "hot reload": { + "enabled": true + }, + "renderer": { + "shader": { + "mode": 1, + "scalar": 16, + "parameters": [ 0, 0, 0, "time" ] + }, + "clear values": [ + [ 1, 1, 1, 0 ] + ] + } + }, + "metadata": { + "menus": { + "pause": "/gui/pause/menu.json" + }, + "bloom": { + "scale": 1.0, + "strength": 1.0, + "sigma": 2.0, + "samples": 2 + }, + "light": { + "exposure": 1.0, + "gamma": 1.0, + "brightnessThreshold": 1.2, + + "ambient": [ 0.15, 0.15, 0.15 ], + + "fog": { + "color": [ 0.5, 0.5, 0.5 ], + "range": [ 8, 256 ], + "step scale": 2, + "absorbtion": 0.07, + "density": { + "threshold": 0.35, + "multiplier": 5.0, + "scale": 25.0, + "offset": [0.2, 0, 1], + "timescale": 8 + } + }, + "should": true, + "shadows": true + }, + "noise": { + "size": [ 16, 16, 16 ] + } + } +} \ No newline at end of file diff --git a/bin/data/scenes/sh2_mcdonalds/scripts/door.lua b/bin/data/scenes/sh2_mcdonalds/scripts/door.lua new file mode 100644 index 00000000..accdcce0 --- /dev/null +++ b/bin/data/scenes/sh2_mcdonalds/scripts/door.lua @@ -0,0 +1,107 @@ +local scene = entities.currentScene() +local controller = entities.controller() + +local timer = Timer.new() +if not timer:running() then + timer:start(); +end + +local polarity = 1 +local state = 0 +local targetAlpha = 1 +local alpha = 0 +local target = Vector3f(0,0,0) +local transform = ent:getComponent("Transform") +local metadata = ent:getComponent("Metadata") +local speed = metadata["speed"] or 1.0 +local normal = Vector3f(0,0,-1) +if metadata["normal"] ~= nil then + local sign = -1 + if metadata["angle"] < 0 then sign = 1 end + normal = Vector3f( metadata["normal"][1] * sign, metadata["normal"][2] * sign, metadata["normal"][3] * sign ):normalize() +end +local starting = Quaternion(transform.orientation) +local ending = transform.orientation:multiply(Quaternion.axisAngle( Vector3f(0,1,0), metadata["angle"] )) +local soundEmitter = ent:loadChild("./sound.json",true) +local playSound = function( key, loop ) + if not loop then loop = false end + local url = "/door/" .. key .. ".ogg" + soundEmitter:queueHook("sound:Emit.%UID%", { + filename = string.resolveURI(url, metadata["system"]["root"]), + spatial = true, + streamed = true, + volume = "sfx", + loop = loop + }, 0) +end +local stopSound = function( key ) + local url = "/door/" .. key .. ".ogg" + soundEmitter:queueHook("sound:Stop.%UID%", { + filename = string.resolveURI(url, metadata["system"]["root"]) + }, 0) +end +local playSoundscape = function( key ) + local url = "/soundscape/" .. key .. ".ogg" + soundEmitter:queueHook("sound:Emit.%UID%", { + filename = string.resolveURI(url, metadata["system"]["root"]), + spatial = false, + volume = "sfx", + loop = true, + streamed = true + }, 0) +end +local stopSoundscape = function( key ) + local url = "/soundscape/" .. key .. ".ogg" + soundEmitter:queueHook("sound:Stop.%UID%", { + filename = string.resolveURI(url, metadata["system"]["root"]) + }, 0) +end +soundEmitter:getComponent("Transform"):setReference( transform ) +-- on tick +ent:bind( "tick", function(self) +-- transform.orientation = starting:slerp( ending, math.cos(time.current() * speed) * 0.5 + 0.5 ) + if state == 1 then + alpha = alpha + time.delta() * speed + + if alpha > targetAlpha then + state = 2 + alpha = targetAlpha + playSound("default_stop") + end + + end + if state == 3 then + alpha = alpha - time.delta() * speed + + if alpha < 0 then + state = 0 + alpha = 0 + playSound("default_stop") + end + end + + if state > 0 then + transform.orientation = starting:slerp( ending, alpha * polarity ) + end +end ) +-- on use +ent:addHook( "entity:Use.%UID%", function( payload ) + if state == 0 or state == 3 then + state = 1 + playSound("default_move") + if payload.uid ~= nil then + local player = entities.get( payload.uid ) + local pTransform = player:getComponent("Transform") + local delta = transform.position - pTransform.position + local side = normal:dot(delta) + if side > 0 then + polarity = 1 + elseif side < 0 then + polarity = -1 + end + end + elseif state == 2 or state == 1 then + state = 3 + playSound("default_move") + end +end ) \ No newline at end of file diff --git a/bin/data/scenes/sh2_mcdonalds/scripts/realign.lua b/bin/data/scenes/sh2_mcdonalds/scripts/realign.lua new file mode 100644 index 00000000..84527d13 --- /dev/null +++ b/bin/data/scenes/sh2_mcdonalds/scripts/realign.lua @@ -0,0 +1,22 @@ +local scene = entities.currentScene() +local controller = entities.controller() + +local timer = Timer.new() +if not timer:running() then + timer:start(); +end + +local transform = ent:getComponent("Transform") +-- on tick +ent:bind( "tick", function(self) + local offset = Vector3f(0,0,0) + if window.keyPressed("J") then offset.x = offset.x - time.delta() end + if window.keyPressed("L") then offset.x = offset.x + time.delta() end + if window.keyPressed("N") then offset.y = offset.y - time.delta() end + if window.keyPressed("M") then offset.y = offset.y + time.delta() end + if window.keyPressed("I") then offset.z = offset.z - time.delta() end + if window.keyPressed("K") then offset.z = offset.z + time.delta() end + if offset:magnitude() > 0.0001 then + transform.position = transform.position + offset + end +end ) \ No newline at end of file diff --git a/bin/data/scenes/sh2_mcdonalds/scripts/static.lua b/bin/data/scenes/sh2_mcdonalds/scripts/static.lua new file mode 100644 index 00000000..085af29f --- /dev/null +++ b/bin/data/scenes/sh2_mcdonalds/scripts/static.lua @@ -0,0 +1,90 @@ +local scene = entities.currentScene() +local controller = entities.controller() + +local timer = Timer.new() +if not timer:running() then + timer:start(); +end +-- release control +--[[ +hooks.call("window:Mouse.CursorVisibility", { state = true }) +hooks.call("window:Mouse.Lock", {}); +]] +-- on tick +ent:bind( "tick", function(self) + -- update static effect + local metadatas = { + ent = ent:getComponent("Metadata"), + scene = scene:getComponent("Metadata") + } + local transforms = { + ent = ent:getComponent("Transform"), + controller = controller:getComponent("Transform") + } + local distanceSquared = transforms.controller.position:distance( transforms.ent.position ) + distanceSquared = distanceSquared * distanceSquared + if type(metadatas.ent["static"]["scale"]) == "number" then + distanceSquared = distanceSquared * metadatas.ent["static"]["scale"] + end + local lo = type(metadatas.ent["static"]["range"][1]) == "number" and metadatas.ent["static"]["range"][1] or 0.1 + local hi = type(metadatas.ent["static"]["range"][2]) == "number" and metadatas.ent["static"]["range"][2] or 0.5 + local staticBlend = distanceSquared > 1 and 1.0 / distanceSquared or 1.0 + staticBlend = math.clamp( staticBlend, lo, hi ) + + local flicker = type(metadatas.ent["static"]["flicker"]) == "number" and metadatas.ent["static"]["flicker"] or 0.001 + local pieces = type(metadatas.ent["static"]["pieces"]) == "number" and metadatas.ent["static"]["pieces"] or 1000 + + local payload = { + mode = 2, + parameters = { + [1] = flicker, + [2] = pieces, + [3] = staticBlend, + [4] = "time" + } + } + scene:callHook("shader:Update.%UID%", payload) +end ) + +--[[ +local hud = ent:loadChild("/hud.json", true) +hud:bind( "tick", function(self) + -- update distance HUD element + if timer:elapsed() <= 0.0125 then return end + timer:reset() + + local metadata = self:getComponent("Metadata") + local transforms = { + controller = controller:getComponent("Transform"), + source = ent:getComponent("Transform") + } + local distance = transforms.controller.position:distance( transforms.source.position ) + --distance = string.si( distance, "m" ) + local maximum = 40 + local value = math.floor(distance/maximum * 100) + if value >= 100 then value = 100 end + distance = "Sanity: " .. value .. "%" + --distance = math.floor((15-distance)/15 * 100) .. "%" + if metadata["text settings"]["string"] ~= distance then + self:callHook( "gui:UpdateString.%UID%", { + string = distance + } ) + end +end ) +]] +--[[ +local marker = ent:loadChild("./marker.json", true) +marker:bind( "tick", function(self) + local transform = marker:getComponent("Transform") + local parentTransform = ent:getComponent("Transform") + local controllerTransform = controller:getComponent("Transform") + + local controllerCamera = controller:getComponent("Camera") + local controllerCameraTransform = controllerCamera:getTransform() + + transform.position = parentTransform.position + Vector3f(0,3,0) + transform.orientation = Quaternion.lookAt( transform.position - controllerTransform.position, Vector3f(0,1,0) ) + -- transform.orientation = transform.orientation:normalize() + -- transform.model = controllerCamera:getProjection() * controllerCamera:getView() * Matrix4f.translate( transform.position ) * transform.orientation:matrix() +end ) +]] \ No newline at end of file diff --git a/bin/data/scenes/sh2_mcdonalds/scripts/trackPlayer.lua b/bin/data/scenes/sh2_mcdonalds/scripts/trackPlayer.lua new file mode 100644 index 00000000..c80bbb38 --- /dev/null +++ b/bin/data/scenes/sh2_mcdonalds/scripts/trackPlayer.lua @@ -0,0 +1,11 @@ +local scene = entities.currentScene() +local controller = entities.controller() + +local transform = ent:getComponent("Transform") +local controllerTransform = controller:getComponent("Transform") +local offset = Vector3f(0,1,0) -- transform.position +io.print("TRACKING PLAYER") +-- on tick +ent:bind( "tick", function(self) + transform.position = offset + controllerTransform.position +end ) \ No newline at end of file diff --git a/bin/data/scenes/sh2_mcdonalds/sh2_mcdonalds.json b/bin/data/scenes/sh2_mcdonalds/sh2_mcdonalds.json new file mode 100644 index 00000000..b28e64c7 --- /dev/null +++ b/bin/data/scenes/sh2_mcdonalds/sh2_mcdonalds.json @@ -0,0 +1,110 @@ +{ + "import": "/model.json", + "assets": [ + // { "filename": "./static.json", "delay": 8 }, + + { "filename": "./models/sh_mcd.glb", "delay": 0, "single threaded": false } + // { "filename": "./models/sh_mcd/graph.json", "delay": 0, "single threaded": false, "category": "models" } + // { "filename": "./models/sh_mcd/graph.json.gz", "delay": 0, "single threaded": false, "category": "models" } + ], + "metadata": { + "model": { + "cull mode": "none", + "alpha mode": "BLEND", + "grid": { + "/^worldspawn/": { + "size": [4,4,4], + // "epsilon": 0.01, + "cleanup": true, + "print": true + }, + "/^worldspawn_sh2/": { + "size": [32,32,32], + // "epsilon": 0.01, + "cleanup": true, + "print": true + } + }, + "tags": { + "worldspawn": { "physics": { "type": "mesh", "static": true } }, + // "worldspawn_sh2": { "physics": { "type": "mesh", "static": true } }, + "info_player_spawn": { "action": "attach", "filename": "./player.json", "preserve orientation": true }, + + "func_door_rotating_5409": { "action": "load", "payload": { "import": "./door.json", "metadata": { "angle":-1.570795, "normal": [-1,0,0] } } }, + "func_door_rotating_5487": { "action": "load", "payload": { "import": "./door.json", "metadata": { "angle": 1.570795, "normal": [ 1,0,0] } } }, + "func_door_rotating_5495": { "action": "load", "payload": { "import": "./door.json", "metadata": { "angle": 1.570795, "normal": [ 1,0,0] } } }, + "func_door_rotating_5656": { "action": "load", "payload": { "import": "./door.json", "metadata": { "angle": 1.570795, "normal": [ 1,0,0] } } }, + "func_door_rotating_5664": { "action": "load", "payload": { "import": "./door.json", "metadata": { "angle":-1.570795, "normal": [-1,0,0] } } }, + "func_door_rotating_5689": { "action": "load", "payload": { "import": "./door.json", "metadata": { "angle":-1.570795, "normal": [-1,0,0] } } }, + "func_door_rotating_5698": { "action": "load", "payload": { "import": "./door.json", "metadata": { "angle":-1.570795, "normal": [-1,0,0] } } }, + "func_door_rotating_5712": { "action": "load", "payload": { "import": "./door.json", "metadata": { "angle":-1.570795, "normal": [-1,0,0] } } }, + + "func_physbox_5212": { "action": "load", "payload": { "import": "./door.json", "metadata": { "angle":-1.570795, "normal": [-1,0,0] } } }, + "func_physbox_5548": { "action": "load", "payload": { "import": "./door.json", "metadata": { "angle":-1.570795, "normal": [-1,0,0] } } }, + "func_physbox_5931": { "action": "load", "payload": { "import": "./door.json", "metadata": { "angle":-1.570795, "normal": [-1,0,0] } } }, + + "func_door_rotating_5568": { "action": "load", "payload": { "import": "./door.json", "metadata": { "angle":-1.570795, "normal": [-1,0,0] } } }, + "func_door_rotating_5576": { "action": "load", "payload": { "import": "./door.json", "metadata": { "angle":-1.570795, "normal": [-1,0,0] } } }, + "func_door_rotating_5584": { "action": "load", "payload": { "import": "./door.json", "metadata": { "angle":-1.570795, "normal": [-1,0,0] } } }, + + "func_physbox_5212": { "action": "load", "payload": { "import": "./prop.json" } }, + "func_physbox_5548": { "action": "load", "payload": { "import": "./prop.json" } }, + "func_physbox_5931": { "action": "load", "payload": { "import": "./prop.json" } }, + "func_physbox_multiplayer_5839": { "action": "load", "payload": { "import": "./prop.json" } }, + "func_physbox_multiplayer_5848": { "action": "load", "payload": { "import": "./prop.json" } }, + "func_physbox_multiplayer_5857": { "action": "load", "payload": { "import": "./prop.json" } }, + "func_physbox_multiplayer_5864": { "action": "load", "payload": { "import": "./prop.json" } }, + "func_physbox_multiplayer_5872": { "action": "load", "payload": { "import": "./prop.json" } }, + "func_physbox_multiplayer_5879": { "action": "load", "payload": { "import": "./prop.json" } }, + "func_physbox_multiplayer_5886": { "action": "load", "payload": { "import": "./prop.json" } }, + "func_physbox_multiplayer_5893": { "action": "load", "payload": { "import": "./prop.json" } }, + "func_physbox_multiplayer_5905": { "action": "load", "payload": { "import": "./prop.json" } }, + "func_physbox_multiplayer_5913": { "action": "load", "payload": { "import": "./prop.json" } }, + "prop_physics_multiplayer_5563": { "action": "load", "payload": { "import": "./prop.json" } }, + "prop_physics_multiplayer_5564": { "action": "load", "payload": { "import": "./prop.json" } }, + "prop_physics_multiplayer_5687": { "action": "load", "payload": { "import": "./prop.json" } }, + "prop_physics_multiplayer_5719": { "action": "load", "payload": { "import": "./prop.json" } }, + "prop_physics_multiplayer_5721": { "action": "load", "payload": { "import": "./prop.json" } }, + "prop_physics_multiplayer_5722": { "action": "load", "payload": { "import": "./prop.json" } }, + "prop_physics_multiplayer_5815": { "action": "load", "payload": { "import": "./prop.json" } }, + "prop_physics_multiplayer_5816": { "action": "load", "payload": { "import": "./prop.json" } }, + "prop_physics_multiplayer_5817": { "action": "load", "payload": { "import": "./prop.json" } }, + "prop_physics_multiplayer_5818": { "action": "load", "payload": { "import": "./prop.json" } }, + "prop_physics_multiplayer_5819": { "action": "load", "payload": { "import": "./prop.json" } }, + "prop_physics_multiplayer_5820": { "action": "load", "payload": { "import": "./prop.json" } }, + "prop_physics_multiplayer_5821": { "action": "load", "payload": { "import": "./prop.json" } }, + "prop_physics_override_5227": { "action": "load", "payload": { "import": "./prop.json" } }, + "prop_physics_override_5373": { "action": "load", "payload": { "import": "./prop.json" } }, + "prop_physics_override_5374": { "action": "load", "payload": { "import": "./prop.json" } }, + "prop_physics_override_5375": { "action": "load", "payload": { "import": "./prop.json" } }, + "prop_physics_override_5545": { "action": "load", "payload": { "import": "./prop.json" } }, + "prop_physics_override_5546": { "action": "load", "payload": { "import": "./prop.json" } }, + "prop_physics_override_5565": { "action": "load", "payload": { "import": "./prop.json" } }, + "prop_physics_override_5566": { "action": "load", "payload": { "import": "./prop.json" } }, + "prop_physics_override_5591": { "action": "load", "payload": { "import": "./prop.json" } }, + "prop_physics_override_5675": { "action": "load", "payload": { "import": "./prop.json" } }, + "prop_physics_override_5680": { "action": "load", "payload": { "import": "./prop.json" } }, + "prop_physics_override_5681": { "action": "load", "payload": { "import": "./prop.json" } }, + "prop_physics_override_5682": { "action": "load", "payload": { "import": "./prop.json" } }, + "prop_physics_override_5683": { "action": "load", "payload": { "import": "./prop.json" } }, + "prop_physics_override_5684": { "action": "load", "payload": { "import": "./prop.json" } }, + "prop_physics_override_5685": { "action": "load", "payload": { "import": "./prop.json" } }, + "prop_physics_override_5696": { "action": "load", "payload": { "import": "./prop.json" } }, + "prop_physics_override_5707": { "action": "load", "payload": { "import": "./prop.json" } }, + "prop_physics_override_5723": { "action": "load", "payload": { "import": "./prop.json" } }, + "prop_physics_override_5749": { "action": "load", "payload": { "import": "./prop.json" } }, + "prop_physics_override_5750": { "action": "load", "payload": { "import": "./prop.json" } }, + "prop_physics_override_5760": { "action": "load", "payload": { "import": "./prop.json" } }, + "prop_physics_override_5764": { "action": "load", "payload": { "import": "./prop.json" } }, + "prop_physics_override_5787": { "action": "load", "payload": { "import": "./prop.json" } }, + "prop_physics_override_5807": { "action": "load", "payload": { "import": "./prop.json" } }, + "prop_physics_override_5808": { "action": "load", "payload": { "import": "./prop.json" } }, + "prop_physics_override_5809": { "action": "load", "payload": { "import": "./prop.json" } }, + "prop_physics_override_5810": { "action": "load", "payload": { "import": "./prop.json" } }, + "prop_physics_override_5814": { "action": "load", "payload": { "import": "./prop.json" } }, + "prop_physics_override_5822": { "action": "load", "payload": { "import": "./prop.json" } }, + "prop_physics_override_5824": { "action": "load", "payload": { "import": "./prop.json" } } + } + } + } +} \ No newline at end of file diff --git a/bin/data/scenes/sh2_mcdonalds/sound.json b/bin/data/scenes/sh2_mcdonalds/sound.json new file mode 100644 index 00000000..351f92fe --- /dev/null +++ b/bin/data/scenes/sh2_mcdonalds/sound.json @@ -0,0 +1,34 @@ +{ + "type": "Object", + "name": "Sound Emitter", + "ignore": false, + "assets": [ + ], + "behaviors": [ + "SoundEmitterBehavior" + ], + "transform": { + "reference": true + }, + "system": { + "hot reload": { + "enabled": true + }, + "defaults": { + "render": true, + "asset load": true + }, + "load": { + "ignore": true + } + }, + "metadata": { + "audio": { + "spatial": true, + "loop": false, + "volume": 1, + "rolloffFactor": 0.5, + "epsilon": 0.5 + } + } +} \ No newline at end of file diff --git a/bin/data/scenes/sh2_mcdonalds/static.json b/bin/data/scenes/sh2_mcdonalds/static.json new file mode 100644 index 00000000..e02750f9 --- /dev/null +++ b/bin/data/scenes/sh2_mcdonalds/static.json @@ -0,0 +1,48 @@ +{ + "type": "Object", + "name": "Static Emitter", + "ignore": false, + "assets": [ + "/overworld/static.ogg", + "./scripts/static.lua" + ], + "behaviors": [ + "SoundEmitterBehavior" + ], + "transform": { + "position": [ -13.4342, 2.43658, 298.797 ], + "rotation": { + "axis": [ 0, 1, 0 ], + "angle": 0 + }, + "scale": [ 1, 1, 1 ] + }, + "system": { + "hot reload": { + "enabled": true + }, + "defaults": { + "render": true, + "asset load": true + }, + "load": { + "ignore": true + } + }, + "metadata": { + "audio": { + "spatial": true, + "loop": true, + "streamed": false, + "volume": 1.6, + "rolloffFactor": 2 + }, + "static": { + "range": [ 0.0025, 1 ], + "flicker": 0.5, + "pieces": 16, + "scale": 0.4 + }, + "distance": false + } +} \ No newline at end of file diff --git a/bin/data/scenes/ss2/medsci.json b/bin/data/scenes/ss2/medsci.json index ec31a1cb..22ba34a3 100644 --- a/bin/data/scenes/ss2/medsci.json +++ b/bin/data/scenes/ss2/medsci.json @@ -1,15 +1,16 @@ { "import": "/model.json", "assets": [ + // { "filename": "./craeture.json", "delay": 1 }, + // { "filename": "./models/tiny_msci.glb", "delay": 0, "single threaded": false, "category": "models" } // { "filename": "./models/tiny_msci/graph.json", "delay": 0, "single threaded": false, "category": "models" } - { "filename": "./models/tiny_msci/graph.json.gz", "delay": 0, "single threaded": false, "category": "models" } + // { "filename": "./models/tiny_msci/graph.json.gz", "delay": 0, "single threaded": false, "category": "models" } // { "filename": "./models/micro_sci.glb", "delay": 0, "single threaded": false, "category": "models" } // { "filename": "./models/micro_sci/graph.json", "delay": 0, "single threaded": false, "category": "models" } - // { "filename": "./models/micro_sci/graph.json.gz", "delay": 0, "single threaded": false, "category": "models" } + { "filename": "./models/micro_sci/graph.json.gz", "delay": 0, "single threaded": false, "category": "models" } - // { "filename": "./craeture.json", "delay": 1 } // { "filename": "./models/msci.glb", "delay": 0, "single threaded": false, "category": "models" } // { "filename": "./models/msci/graph.json", "delay": 0, "single threaded": false, "category": "models" } @@ -21,31 +22,17 @@ ], "metadata": { "model": { - "exporter": { - "enabled": true - }, - "baking": { - "enabled": false, - "resolution": 2048, // 8192 - "shadows": 1024, - "layers": 22, - "trigger": { "mode": "rendered" }, - // "trigger": { "mode": "key", "value": "B" }, - "output": "./lightmap.%i.png" - }, - "grid": { - "/^worldspawn/": { - "size": [3,3,3] - } - }, -// "lightmap": "./lightmap.%i.min.png", -// "lightmap": false, "lightmap": true, + "baking": { + "enabled": true, + "resolution": 1024 + }, "filter": "LINEAR", "tags": { - "worldspawn": { "physics": { "type": "mesh", "static": true } }, - "worldspawn_20": { "physics": { "type": "mesh", "static": true } }, - // "worldspawn": { "physics": { "type": "bounding boxes", "static": true } }, + "/^worldspawn/": { + "physics": { "type": "mesh", "static": true }, + "grid": { "size": [5,2,5], "epsilon": 1.0, "cleanup": true, "print": true } + }, "info_player_spawn": { "action": "attach", "filename": "./player.json", diff --git a/bin/data/shaders/common/functions.h b/bin/data/shaders/common/functions.h index 932c8719..f77661a1 100644 --- a/bin/data/shaders/common/functions.h +++ b/bin/data/shaders/common/functions.h @@ -32,6 +32,19 @@ vec2 encodeNormals( vec3 n ) { // return n.xy/p + 0.5; return (vec2(atan(n.y,n.x)/PI, n.z)+1.0)*0.5; } +vec3 encodeSrgb(vec3 rgb) { + const vec3 a = 12.92 * rgb; + const vec3 b = 1.055 * pow(rgb, vec3(1.0 / 2.4)) - 0.055; + const vec3 c = step(vec3(0.0031308), rgb); + return mix(a, b, c); +} + +vec3 decodeSrgb(vec3 rgb) { + const vec3 a = rgb / 12.92; + const vec3 b = pow((rgb + 0.055) / 1.055, vec3(2.4)); + const vec3 c = step(vec3(0.04045), rgb); + return mix(a, b, c); +} bool validTextureIndex( int textureIndex ) { return 0 <= textureIndex && textureIndex < MAX_TEXTURES; } diff --git a/bin/data/shaders/common/lambert.h b/bin/data/shaders/common/lambert.h index 5418b2aa..a70a2920 100644 --- a/bin/data/shaders/common/lambert.h +++ b/bin/data/shaders/common/lambert.h @@ -21,7 +21,7 @@ void lambert() { const vec3 diffuse = surface.material.albedo.rgb; const vec3 specular = vec3(0); - surface.fragment.rgb += (diffuse + specular) * Lr * cosLi; - surface.fragment.a += light.power * La * Ls; + surface.light.rgb += (diffuse + specular) * Lr * cosLi; + surface.light.a += light.power * La * Ls; } } \ No newline at end of file diff --git a/bin/data/shaders/common/light.h b/bin/data/shaders/common/light.h new file mode 100644 index 00000000..f708b70d --- /dev/null +++ b/bin/data/shaders/common/light.h @@ -0,0 +1,9 @@ +#if PBR + #include "../common/pbr.h" +#endif +#if LAMBERT + #include "../common/lambert.h" +#endif +#if PHONG + #include "../common/phong.h" +#endif \ No newline at end of file diff --git a/bin/data/shaders/common/pbr.h b/bin/data/shaders/common/pbr.h index a387b96b..cfe85745 100644 --- a/bin/data/shaders/common/pbr.h +++ b/bin/data/shaders/common/pbr.h @@ -13,7 +13,7 @@ float gaSchlickGGX(float cosLi, float cosLo, float roughness) { return gaSchlickG1(cosLi, k) * gaSchlickG1(cosLo, k); } vec3 fresnelSchlick(vec3 F0, float cosTheta) { return F0 + (1.0 - F0) * pow(1.0 - cosTheta, 5.0); } -#if !BAKING +#if !BAKING && !COMPUTE void pbr() { if ( validTextureIndex( surface.instance.lightmapID ) ) return; @@ -42,13 +42,15 @@ void pbr() { const float G = gaSchlickGGX(cosLi, cosLo, surface.material.roughness); const vec3 diffuse = mix( vec3(1.0) - F, vec3(0.0), surface.material.metallic ) * surface.material.albedo.rgb; const vec3 specular = (F * D * G) / max(EPSILON, 4.0 * cosLi * cosLo); + /* // lightmapped, compute only specular - if ( light.type >= 0 && validTextureIndex( surface.instance.lightmapID ) ) surface.fragment.rgb += (specular) * Lr * cosLi; + if ( light.type >= 0 && validTextureIndex( surface.instance.lightmapID ) ) surface.light.rgb += (specular) * Lr * cosLi; // point light, compute only diffuse - // else if ( abs(light.type) == 1 ) surface.fragment.rgb += (diffuse) * Lr * cosLi; - else surface.fragment.rgb += (diffuse + specular) * Lr * cosLi; - surface.fragment.rgb += (diffuse + specular) * Lr * cosLi; - surface.fragment.a += light.power * La * Ls; + // else if ( abs(light.type) == 1 ) surface.light.rgb += (diffuse) * Lr * cosLi; + else surface.light.rgb += (diffuse + specular) * Lr * cosLi; + */ + surface.light.rgb += (diffuse + specular) * Lr * cosLi; + surface.light.a += light.power * La * Ls; } } #endif \ No newline at end of file diff --git a/bin/data/shaders/common/structs.h b/bin/data/shaders/common/structs.h index bd7e935e..09d3bd77 100644 --- a/bin/data/shaders/common/structs.h +++ b/bin/data/shaders/common/structs.h @@ -158,6 +158,7 @@ struct Surface { SurfaceMaterial material; Instance instance; + vec4 light; vec4 fragment; } surface; diff --git a/bin/data/shaders/common/vxgi.h b/bin/data/shaders/common/vxgi.h index d7f84276..49f80c43 100644 --- a/bin/data/shaders/common/vxgi.h +++ b/bin/data/shaders/common/vxgi.h @@ -162,7 +162,7 @@ void indirectLighting() { indirectSpecular = voxelConeTrace( ray, SPECULAR_CONE_APERTURE ); // outFragColor.rgb = indirectSpecular.rgb; return; if ( length(indirectSpecular) < 0.0125 ) { - // indirectSpecular += (1.0 - indirectSpecular.a) * texture( samplerSkybox, R ); + // indirectSpecular += (1.0 - indirectSpecular.a) * texture( samplerCubemaps[ubo.indexSkybox], R ) * SPECULAR_CONE_APERTURE; } } diff --git a/bin/data/shaders/display/subpass.h b/bin/data/shaders/display/subpass.h index 2fb64708..7691c954 100644 --- a/bin/data/shaders/display/subpass.h +++ b/bin/data/shaders/display/subpass.h @@ -101,7 +101,7 @@ layout (location = 1) out vec4 outFragBright; #include "../common/functions.h" #include "../common/fog.h" -#include "../common/pbr.h" +#include "../common/light.h" #include "../common/shadows.h" #if VXGI #include "../common/vxgi.h" @@ -236,11 +236,11 @@ void populateSurface() { } // Lightmap if ( validTextureIndex( surface.instance.lightmapID ) ) { - surface.material.albedo.rgb *= sampleTexture( surface.instance.lightmapID, surface.st ).rgb; + surface.light += surface.material.albedo * sampleTexture( surface.instance.lightmapID, surface.st ); } // Emissive textures if ( validTextureIndex( material.indexEmissive ) ) { - surface.material.albedo += sampleTexture( material.indexEmissive ); + surface.light += sampleTexture( material.indexEmissive ); } // Occlusion map if ( validTextureIndex( material.indexOcclusion ) ) { @@ -262,15 +262,8 @@ void populateSurface() { } void directLighting() { - const vec3 ambient = ubo.ambient.rgb * surface.material.occlusion + surface.material.indirect.rgb; -// surface.fragment.rgb += surface.material.albedo.rgb * ambient; - - if ( validTextureIndex( surface.instance.lightmapID ) ) { - surface.fragment.rgb += surface.material.albedo.rgb + ambient; - } else { - surface.fragment.rgb += surface.material.albedo.rgb * ambient; - } -// if ( ubo.lights == 0 ) { surface.fragment.rgb = surface.material.albedo.rgb; return; } + surface.light.rgb += surface.material.albedo.rgb * ubo.ambient.rgb * surface.material.occlusion; // add ambient lighting + surface.light.rgb += surface.material.indirect.rgb; // add indirect lighting #if PBR pbr(); #elif LAMBERT @@ -278,6 +271,7 @@ void directLighting() { #elif PHONG phong(); #endif + surface.fragment.rgb += surface.light.rgb; } #if MULTISAMPLING diff --git a/bin/data/shaders/display/vxgi.comp.h b/bin/data/shaders/display/vxgi.comp.h index d3db68e6..a31ffeee 100644 --- a/bin/data/shaders/display/vxgi.comp.h +++ b/bin/data/shaders/display/vxgi.comp.h @@ -4,8 +4,8 @@ layout (local_size_x = 8, local_size_y = 8, local_size_z = 8) in; -#define LAMBERT 1 -#define PBR 0 +#define LAMBERT 0 +#define PBR 1 #define VXGI 1 #define COMPUTE 1 @@ -72,6 +72,7 @@ layout (binding = 13, rg16f) uniform volatile coherent image3D voxelNormal[CASCA #endif #include "../common/functions.h" +#include "../common/light.h" #undef VXGI #include "../common/shadows.h" @@ -96,6 +97,7 @@ void main() { const Material material = materials[surface.instance.materialID]; surface.material.albedo = material.colorBase; surface.fragment = material.colorEmissive; +/* #if DEFERRED_SAMPLING { vec4 uv = imageLoad(voxelUv[CASCADE], ivec3(tUvw) ); @@ -127,20 +129,19 @@ void main() { #else surface.material.albedo = imageLoad(voxelRadiance[CASCADE], ivec3(tUvw) ); #endif +*/ + surface.material.albedo = imageLoad(voxelRadiance[CASCADE], ivec3(tUvw) ); surface.material.metallic = material.factorMetallic; surface.material.roughness = material.factorRoughness; surface.material.occlusion = material.factorOcclusion; - float litFactor = 1.0; + const vec3 ambient = ubo.ambient.rgb * surface.material.occlusion; if ( validTextureIndex( surface.instance.lightmapID ) ) { - surface.fragment.rgb += surface.material.albedo.rgb + ubo.ambient.rgb * surface.material.occlusion; + surface.fragment.rgb += surface.material.albedo.rgb; } else { - surface.fragment.rgb += surface.material.albedo.rgb * ubo.ambient.rgb * surface.material.occlusion; - } - // corrections - surface.material.roughness *= 4.0; - if ( !validTextureIndex( surface.instance.lightmapID ) ) - { + surface.fragment.rgb += surface.material.albedo.rgb * ambient; + // corrections + surface.material.roughness *= 4.0; const vec3 F0 = mix(vec3(0.04), surface.material.albedo.rgb, surface.material.metallic); const vec3 Lo = normalize( surface.position.world ); const float cosLo = max(0.0, dot(surface.normal.world, Lo)); @@ -171,14 +172,19 @@ void main() { const vec3 specular = (F * D * G) / max(EPSILON, 4.0 * cosLi * cosLo); #endif // lightmapped, compute only specular - if ( light.type >= 0 && validTextureIndex( surface.instance.lightmapID ) ) surface.fragment.rgb += (specular) * Lr * cosLi; + /* + if ( light.type >= 0 && validTextureIndex( surface.instance.lightmapID ) ) surface.light.rgb += (specular) * Lr * cosLi; // point light, compute only diffuse - // else if ( abs(light.type) == 1 ) surface.fragment.rgb += (diffuse) * Lr * cosLi; - else surface.fragment.rgb += (diffuse + specular) * Lr * cosLi; - surface.fragment.a += light.power * La * Ls; + // else if ( abs(light.type) == 1 ) surface.light.rgb += (diffuse) * Lr * cosLi; + else surface.light.rgb += (diffuse + specular) * Lr * cosLi; + */ + surface.light.rgb += (diffuse + specular) * Lr * cosLi; + surface.light.a += light.power * La * Ls; } } + surface.fragment.rgb += surface.light.rgb; + imageStore(voxelRadiance[CASCADE], ivec3(tUvw), vec4(surface.fragment.rgb, surface.material.albedo.a)); } } \ No newline at end of file diff --git a/bin/data/shaders/graph/baking/bake.frag.glsl b/bin/data/shaders/graph/baking/bake.frag.glsl index fcb09737..f91458e3 100644 --- a/bin/data/shaders/graph/baking/bake.frag.glsl +++ b/bin/data/shaders/graph/baking/bake.frag.glsl @@ -67,8 +67,9 @@ void main() { surface.material.roughness = material.factorRoughness; surface.material.occlusion = 1.0f - material.factorOcclusion; - surface.fragment = material.colorEmissive; + surface.light = material.colorEmissive; surface.material.albedo = vec4(1); +#if 1 { const vec3 F0 = mix(vec3(0.04), surface.material.albedo.rgb, surface.material.metallic); for ( uint i = 0; i < lights.length(); ++i ) { @@ -107,22 +108,61 @@ void main() { const vec3 diffuse = mix( vec3(1.0) - F, vec3(0.0), surface.material.metallic ) * surface.material.albedo.rgb; const vec3 specular = (F * D * G) / max(EPSILON, 4.0 * cosLi * cosLo); #endif - surface.fragment.rgb += (diffuse + specular) * Lr * cosLi; - surface.fragment.a += light.power * La * Ls; + + surface.light.rgb += (diffuse + specular) * Lr * cosLi; + surface.light.a += light.power * La * Ls; } } +#else + { + // corrections + surface.material.roughness *= 4.0; + const vec3 F0 = mix(vec3(0.04), surface.material.albedo.rgb, surface.material.metallic); + const vec3 Lo = normalize( surface.position.world ); + const float cosLo = max(0.0, dot(surface.normal.world, Lo)); + for ( uint i = 0; i < lights.length(); ++i ) { + const Light light = lights[i]; + if ( light.power <= LIGHT_POWER_CUTOFF ) continue; + if ( light.type >= 0 && validTextureIndex( surface.instance.lightmapID ) ) continue; + const vec3 Lp = light.position; + const vec3 Liu = light.position - surface.position.world; + const vec3 Li = normalize(Liu); + const float Ls = shadowFactor( light, 0.0 ); + const float La = 1.0 / (PI * pow(length(Liu), 2.0)); + if ( light.power * La * Ls <= LIGHT_POWER_CUTOFF ) continue; -#define EXPOSURE 1 -#define GAMMA 1 + const float cosLi = max(0.0, dot(surface.normal.world, Li)); + const vec3 Lr = light.color.rgb * light.power * La * Ls; + #if LAMBERT + const vec3 diffuse = surface.material.albedo.rgb; + const vec3 specular = vec3(0); + #elif PBR + const vec3 Lh = normalize(Li + Lo); + const float cosLh = max(0.0, dot(surface.normal.world, Lh)); + + const vec3 F = fresnelSchlick( F0, max( 0.0, dot(Lh, Lo) ) ); + const float D = ndfGGX( cosLh, surface.material.roughness ); + const float G = gaSchlickGGX(cosLi, cosLo, surface.material.roughness); + const vec3 diffuse = mix( vec3(1.0) - F, vec3(0.0), surface.material.metallic ) * surface.material.albedo.rgb; + const vec3 specular = (F * D * G) / max(EPSILON, 4.0 * cosLi * cosLo); + #endif -// surface.fragment.rgb = vec3(1.0) - exp(-surface.fragment.rgb * EXPOSURE); -// surface.fragment.rgb = pow(surface.fragment.rgb, vec3(1.0 / GAMMA)); + surface.light.rgb += (diffuse + specular) * Lr * cosLi; + surface.light.a += light.power * La * Ls; + } + } +#endif +#define EXPOSURE 0 +#define GAMMA 0 - outAlbedo = vec4(surface.fragment.rgb, 1); +// surface.light.rgb = vec3(1.0) - exp(-surface.light.rgb * EXPOSURE); +// surface.light.rgb = pow(surface.light.rgb, vec3(1.0 / GAMMA)); + + outAlbedo = vec4(surface.light.rgb, 1); { const vec2 st = inSt.xy * imageSize(outAlbedos).xy; const ivec3 uvw = ivec3(int(st.x), int(st.y), int(inLayer)); - imageStore(outAlbedos, uvw, vec4(surface.fragment.rgb, 1) ); + imageStore(outAlbedos, uvw, vec4(surface.light.rgb, 1) ); } } \ No newline at end of file diff --git a/engine/inc/uf/engine/asset/asset.h b/engine/inc/uf/engine/asset/asset.h index acdda9d1..b79b2091 100644 --- a/engine/inc/uf/engine/asset/asset.h +++ b/engine/inc/uf/engine/asset/asset.h @@ -35,6 +35,8 @@ namespace uf { static uf::Asset::Payload resolveToPayload( const uf::stl::string&, const uf::stl::string& = "" ); static bool isExpected( const uf::Asset::Payload&, uf::Asset::Type expected ); + static bool assertionLoad; + // URL or file path void processQueue(); diff --git a/engine/inc/uf/engine/entity/entity.h b/engine/inc/uf/engine/entity/entity.h index 39f0fc14..7c33808c 100644 --- a/engine/inc/uf/engine/entity/entity.h +++ b/engine/inc/uf/engine/entity/entity.h @@ -9,9 +9,7 @@ #include namespace uf { - class UF_API Object; class UF_API Entity : public uf::Behaviors { - //friend class EntityBehavior; public: typedef uf::stl::vector container_t; static uf::Entity null; @@ -36,8 +34,8 @@ namespace uf { std::size_t getUid() const; void setName( const uf::stl::string& ); // cast to other Entity classes, avoid nasty shit like *((uf::Object*) &entity) - template T& as(); - template const T& as() const; + template T& as(); + template const T& as() const; // parent-child relationship bool hasParent() const; template T& getParent(); diff --git a/engine/inc/uf/engine/object/behavior.h b/engine/inc/uf/engine/object/behavior.h index 7d1008c4..f36348fd 100644 --- a/engine/inc/uf/engine/object/behavior.h +++ b/engine/inc/uf/engine/object/behavior.h @@ -44,6 +44,7 @@ namespace uf { } load; bool ignoreGraph = false; + bool invalid = false; } system; struct { pod::Transform<> initial; diff --git a/engine/inc/uf/engine/object/object.h b/engine/inc/uf/engine/object/object.h index 75877cd5..2de0bf3c 100644 --- a/engine/inc/uf/engine/object/object.h +++ b/engine/inc/uf/engine/object/object.h @@ -13,6 +13,8 @@ namespace uf { class UF_API Object : public uf::Entity { public: static uf::Timer timer; + static bool assertionLoad; + Object(); bool reload( bool = false ); diff --git a/engine/inc/uf/utils/thread/thread.h b/engine/inc/uf/utils/thread/thread.h index d45eeab3..800b881c 100644 --- a/engine/inc/uf/utils/thread/thread.h +++ b/engine/inc/uf/utils/thread/thread.h @@ -56,6 +56,7 @@ namespace uf { pod::Thread& UF_API fetchWorker( const uf::stl::string& name = "Aux" ); void UF_API batchWorker( const pod::Thread::function_t&, const uf::stl::string& name = "Aux" ); void UF_API batchWorkers( const uf::stl::vector&, bool = true, const uf::stl::string& name = "Aux" ); + void UF_API batchWorkers_Async( const uf::stl::vector&, bool = true, const uf::stl::string& name = "Aux" ); void UF_API add( pod::Thread&, const pod::Thread::function_t&, bool = false ); void UF_API process( pod::Thread& ); diff --git a/engine/src/engine/asset/asset.cpp b/engine/src/engine/asset/asset.cpp index 58c798b9..60581264 100644 --- a/engine/src/engine/asset/asset.cpp +++ b/engine/src/engine/asset/asset.cpp @@ -47,6 +47,7 @@ namespace { } uf::Asset uf::Asset::masterAssetLoader; +bool uf::Asset::assertionLoad = true; void uf::Asset::processQueue() { uf::thread::batchWorker( [&](){ @@ -223,18 +224,30 @@ uf::stl::string uf::Asset::cache( const uf::Asset::Payload& payload ) { uf::stl::string hash = uf::string::sha256( filename ); uf::stl::string cached = uf::io::root + "/cache/http/" + hash + "." + extension; if ( !uf::io::exists( cached ) && !retrieve( filename, cached, hash ) ) { - UF_MSG_ERROR("Failed to preload `" + filename + "` (`" + cached + "`): HTTP error"); + if ( !uf::Asset::assertionLoad ) { + UF_MSG_ERROR("Failed to preload `" + filename + "` (`" + cached + "`): HTTP error"); + } else { + UF_EXCEPTION("Failed to preload `" + filename + "` (`" + cached + "`): HTTP error"); + } return ""; } filename = cached; } if ( !uf::io::exists( filename ) ) { - UF_MSG_ERROR("Failed to preload `" + filename + "`: Does not exist"); + if ( !uf::Asset::assertionLoad ) { + UF_MSG_ERROR("Failed to preload `" + filename + "`: Does not exist"); + } else { + UF_EXCEPTION("Failed to preload `" + filename + "`: Does not exist"); + } return ""; } uf::stl::string actual = payload.hash; if ( payload.hash != "" && (actual = uf::io::hash( filename )) != payload.hash ) { - UF_MSG_ERROR("Failed to preload `" << filename << "`: Hash mismatch; expected " << payload.hash << ", got " << actual); + if ( !uf::Asset::assertionLoad ) { + UF_MSG_ERROR("Failed to preload `" << filename << "`: Hash mismatch; expected " << payload.hash << ", got " << actual); + } else { + UF_EXCEPTION("Failed to preload `" << filename << "`: Hash mismatch; expected " << payload.hash << ", got " << actual); + } return ""; } return filename; @@ -247,18 +260,30 @@ uf::stl::string uf::Asset::load(const uf::Asset::Payload& payload ) { uf::stl::string hash = uf::string::sha256( payload.filename ); uf::stl::string cached = uf::io::root + "/cache/http/" + hash + "." + extension; if ( !uf::io::exists( cached ) && !retrieve( payload.filename, cached, hash ) ) { - UF_MSG_ERROR("Failed to load `" + payload.filename + "` (`" + cached + "`): HTTP error"); + if ( !uf::Asset::assertionLoad ) { + UF_MSG_ERROR("Failed to load `" + payload.filename + "` (`" + cached + "`): HTTP error"); + } else { + UF_EXCEPTION("Failed to load `" + payload.filename + "` (`" + cached + "`): HTTP error"); + } return ""; } filename = cached; } if ( !uf::io::exists( filename ) ) { - UF_MSG_ERROR("Failed to load `" + filename + "`: Does not exist"); + if ( !uf::Asset::assertionLoad ) { + UF_MSG_ERROR("Failed to load `" + filename + "`: Does not exist"); + } else { + UF_EXCEPTION("Failed to load `" + filename + "`: Does not exist"); + } return ""; } uf::stl::string actual = payload.hash; if ( payload.hash != "" && (actual = uf::io::hash( filename )) != payload.hash ) { - UF_MSG_ERROR("Failed to load `" << filename << "`: Hash mismatch; expected " << payload.hash << ", got " << actual); + if ( !uf::Asset::assertionLoad ) { + UF_MSG_ERROR("Failed to load `" << filename << "`: Hash mismatch; expected " << payload.hash << ", got " << actual); + } else { + UF_EXCEPTION("Failed to load `" << filename << "`: Hash mismatch; expected " << payload.hash << ", got " << actual); + } return ""; } diff --git a/engine/src/engine/graph/decode.cpp b/engine/src/engine/graph/decode.cpp index 56ff080f..f974bb09 100644 --- a/engine/src/engine/graph/decode.cpp +++ b/engine/src/engine/graph/decode.cpp @@ -12,7 +12,7 @@ #if UF_ENV_DREAMCAST #define UF_GRAPH_LOAD_MULTITHREAD 0 #else - #define UF_GRAPH_LOAD_MULTITHREAD 0 + #define UF_GRAPH_LOAD_MULTITHREAD 1 // causes Vulkan OOM #endif namespace { @@ -428,7 +428,7 @@ pod::Graph uf::graph::load( const uf::stl::string& filename, const uf::Serialize graph.root = decodeNode( serializer["root"], graph ); }); #if UF_GRAPH_LOAD_MULTITHREAD - if ( !jobs.empty() ) uf::thread::batchWorkers( jobs ); + if ( !jobs.empty() ) uf::thread::batchWorkers_Async( jobs ); #else for ( auto& job : jobs ) job(); #endif diff --git a/engine/src/engine/graph/encode.cpp b/engine/src/engine/graph/encode.cpp index c3bb8633..1e9f1dcd 100644 --- a/engine/src/engine/graph/encode.cpp +++ b/engine/src/engine/graph/encode.cpp @@ -12,7 +12,7 @@ #if UF_ENV_DREAMCAST #define UF_GRAPH_LOAD_MULTITHREAD 0 #else - #define UF_GRAPH_LOAD_MULTITHREAD 0 + #define UF_GRAPH_LOAD_MULTITHREAD 1 // causes Vulkan OOM #endif namespace { @@ -427,7 +427,7 @@ void uf::graph::save( const pod::Graph& graph, const uf::stl::string& filename ) serializer["root"] = encode(graph.root, settings); }); #if UF_GRAPH_LOAD_MULTITHREAD - if ( !jobs.empty() ) uf::thread::batchWorkers( jobs ); + if ( !jobs.empty() ) uf::thread::batchWorkers_Async( jobs ); #else for ( auto& job : jobs ) job(); #endif diff --git a/engine/src/engine/graph/graph.cpp b/engine/src/engine/graph/graph.cpp index 0c0660fd..fbfc885b 100644 --- a/engine/src/engine/graph/graph.cpp +++ b/engine/src/engine/graph/graph.cpp @@ -367,31 +367,37 @@ void uf::graph::process( pod::Graph& graph ) { // if ( !graph.root.entity ) graph.root.entity = new uf::Object; + // + uf::stl::unordered_map isSrgb; + // process lightmap #if UF_USE_OPENGL #define UF_GRAPH_DEFAULT_LIGHTMAP "./lightmap.%i.min.dtex" #else #define UF_GRAPH_DEFAULT_LIGHTMAP "./lightmap.%i.png" #endif - if ( graph.metadata["lightmap"].as() ) { + { uf::stl::unordered_map filenames; uf::stl::unordered_map lightmapIDs; - - UF_MSG_DEBUG( graph.instances.size() ); + uint32_t lightmapCount = 0; for ( auto& name : graph.instances ) { auto& instance = uf::graph::storage.instances[name]; - // if ( !instance.auxID ) break; filenames[instance.auxID] = uf::string::replace(UF_GRAPH_DEFAULT_LIGHTMAP, "%i", std::to_string(instance.auxID)); + + lightmapCount = std::max( lightmapCount, instance.auxID ); } for ( auto& name : graph.primitives ) { auto& primitives = uf::graph::storage.primitives[name]; for ( auto& primitive : primitives ) { - // if ( !primitive.instance.auxID ) break; filenames[primitive.instance.auxID] = uf::string::replace(UF_GRAPH_DEFAULT_LIGHTMAP, "%i", std::to_string(primitive.instance.auxID)); + + lightmapCount = std::max( lightmapCount, primitive.instance.auxID ); } } - for ( auto& pair : filenames ) { + graph.metadata["baking"]["layers"] = lightmapCount; + + if ( graph.metadata["lightmap"].as() ) for ( auto& pair : filenames ) { auto i = pair.first; auto f = uf::io::sanitize( pair.second, uf::io::directory( graph.name ) ); @@ -399,6 +405,7 @@ void uf::graph::process( pod::Graph& graph ) { UF_MSG_ERROR( "lightmap does not exist: " << f ) continue; } + auto textureID = graph.textures.size(); auto imageID = graph.images.size(); @@ -413,6 +420,8 @@ void uf::graph::process( pod::Graph& graph ) { graph.metadata["lightmaps"][i] = f; graph.metadata["baking"]["enabled"] = false; + + isSrgb[f] = false; } for ( auto& name : graph.instances ) { @@ -427,38 +436,6 @@ void uf::graph::process( pod::Graph& graph ) { primitive.instance.lightmapID = lightmapIDs[primitive.instance.auxID]; } } - #if 0 - const uf::stl::string lightmapFilename = graph.metadata["lightmap"].as(UF_GRAPH_DEFAULT_LIGHTMAP); - // load lightmap, if requested - if ( lightmapFilename != "" ) { - // check if valid filename, if not it's a texture name - uf::stl::string f = uf::io::sanitize( lightmapFilename, uf::io::directory( graph.name ) ); - if ( uf::io::exists( f ) ) { - auto textureID = graph.textures.size(); - auto imageID = graph.images.size(); - - auto& texture = /*graph.storage*/uf::graph::storage.textures[graph.textures.emplace_back(f)]; - auto& image = /*graph.storage*/uf::graph::storage.images[graph.images.emplace_back(f)]; - image.open( f, false ); - - texture.index = imageID; - - for ( auto& name : graph.instances ) { - auto& instance = uf::graph::storage.instances[name]; - instance.lightmapID = textureID; - } - for ( auto& name : graph.primitives ) { - auto& primitives = uf::graph::storage.primitives[name]; - for ( auto& primitive : primitives ) { - primitive.instance.lightmapID = textureID; - } - } - - graph.metadata["lightmapped"] = f; - graph.metadata["baking"]["enabled"] = false; - } - } - #endif } // add atlas @@ -480,19 +457,21 @@ void uf::graph::process( pod::Graph& graph ) { if ( !(0 <= ID && ID < graph.textures.size()) ) continue; auto texName = graph.textures[ID]; - auto& texture = uf::graph::storage.texture2Ds[texName]; - texture.srgb = true; + isSrgb[texName] = true; } for ( auto& key : graph.images ) { auto& image = uf::graph::storage.images[key]; auto& texture = uf::graph::storage.texture2Ds[key]; if ( !texture.generated() ) { - bool isLightmap = graph.metadata["lightmapped"].as() == key; - auto filter = graph.metadata["filter"].as() == "NEAREST" && !isLightmap ? uf::renderer::enums::Filter::NEAREST : uf::renderer::enums::Filter::LINEAR; + // bool isLightmap = graph.metadata["lightmapped"].as() == key; + // auto filter = graph.metadata["filter"].as() == "NEAREST" && !isLightmap ? uf::renderer::enums::Filter::NEAREST : uf::renderer::enums::Filter::LINEAR; // auto filter = uf::renderer::enums::Filter::LINEAR; + + auto filter = graph.metadata["filter"].as() == "NEAREST" ? uf::renderer::enums::Filter::NEAREST : uf::renderer::enums::Filter::LINEAR; texture.sampler.descriptor.filter.min = filter; texture.sampler.descriptor.filter.mag = filter; + texture.srgb = isSrgb.count(key) == 0 ? false : isSrgb[key]; texture.loadFromImage( image ); #if UF_ENV_DREAMCAST @@ -706,40 +685,40 @@ void uf::graph::process( pod::Graph& graph, int32_t index, uf::Object& parent ) // on systems where frametime is very, very important, we can set all static nodes to not tick // tie to tag - { - ext::json::Value info = ext::json::null(); - if ( ext::json::isObject( graph.metadata["tags"][node.name] ) ) { - info = graph.metadata["tags"][node.name]; - } else { - ext::json::forEach( graph.metadata["tags"], [&]( const uf::stl::string& key, ext::json::Value& value ) { - if ( !uf::string::isRegex( key ) ) return; - if ( uf::string::matches( node.name, key ).empty() ) return; - info = value; - }); - } - if ( ext::json::isObject( info ) ) { - if ( info["ignore"].as() ) return; + ext::json::Value tag = ext::json::null(); +/* + if ( ext::json::isObject( graph.metadata["tags"][node.name] ) ) { + tag = graph.metadata["tags"][node.name]; + } +*/ + ext::json::forEach( graph.metadata["tags"], [&]( const uf::stl::string& key, ext::json::Value& value ) { + if ( uf::string::isRegex( key ) ) { + if ( uf::string::matches( node.name, key ).empty() ) return; + } else if ( node.name != key ) return; + tag = value; + }); + if ( ext::json::isObject( tag ) ) { + if ( tag["ignore"].as() ) return; - if ( info["action"].as() == "load" ) { - if ( info["filename"].is() ) { - uf::stl::string filename = uf::io::resolveURI( info["filename"].as(), graph.metadata["root"].as() ); - entity.load(filename); - } else if ( ext::json::isObject( info["payload"] ) ) { - uf::Serializer json = info["payload"]; - json["root"] = graph.metadata["root"]; - entity.load(json); - } - } else if ( info["action"].as() == "attach" ) { - uf::stl::string filename = uf::io::resolveURI( info["filename"].as(), graph.metadata["root"].as() ); - auto& child = entity.loadChild( filename, false ); - auto& childTransform = child.getComponent>(); - auto flatten = uf::transform::flatten( node.transform ); - if ( !info["preserve position"].as() ) childTransform.position = flatten.position; - if ( !info["preserve orientation"].as() ) childTransform.orientation = flatten.orientation; - } - if ( info["static"].is() ) { - metadata.system.ignoreGraph = info["static"].as(); + if ( tag["action"].as() == "load" ) { + if ( tag["filename"].is() ) { + uf::stl::string filename = uf::io::resolveURI( tag["filename"].as(), graph.metadata["root"].as() ); + entity.load(filename); + } else if ( ext::json::isObject( tag["payload"] ) ) { + uf::Serializer json = tag["payload"]; + json["root"] = graph.metadata["root"]; + entity.load(json); } + } else if ( tag["action"].as() == "attach" ) { + uf::stl::string filename = uf::io::resolveURI( tag["filename"].as(), graph.metadata["root"].as() ); + auto& child = entity.loadChild( filename, false ); + auto& childTransform = child.getComponent>(); + auto flatten = uf::transform::flatten( node.transform ); + if ( !tag["preserve position"].as() ) childTransform.position = flatten.position; + if ( !tag["preserve orientation"].as() ) childTransform.orientation = flatten.orientation; + } + if ( tag["static"].is() ) { + metadata.system.ignoreGraph = tag["static"].as(); } } // create as light @@ -790,27 +769,24 @@ void uf::graph::process( pod::Graph& graph, int32_t index, uf::Object& parent ) transform = node.transform; transform.reference = &parent.getComponent>(); // override transform - if ( !ext::json::isNull( graph.metadata["tags"][node.name] ) ) { - auto& info = graph.metadata["tags"][node.name]; - if ( info["transform"]["offset"].as() ) { - auto parsed = uf::transform::decode( info["transform"], pod::Transform<>{} ); - transform.position += parsed.position; - transform.orientation = uf::quaternion::multiply( transform.orientation, parsed.orientation ); - } else { - transform = uf::transform::decode( info["transform"], transform ); - if ( info["transform"]["parent"].is() ) { - auto* parentPointer = uf::graph::find( graph, info["transform"]["parent"].as() ); - if ( parentPointer ) { - auto& parentNode = *parentPointer; - // entity already exists, bind to its transform - if ( parentNode.entity && parentNode.entity->hasComponent>() ) { - auto& parentTransform = parentNode.entity->getComponent>(); - transform = uf::transform::reference( transform, parentTransform, info["transform"]["reorient"].as() ); - transform.position = -transform.position; - // doesnt exist, bind to the node transform - } else { - transform = uf::transform::reference( transform, parentNode.transform, info["transform"]["reorient"].as() ); - } + if ( tag["transform"]["offset"].as() ) { + auto parsed = uf::transform::decode( tag["transform"], pod::Transform<>{} ); + transform.position += parsed.position; + transform.orientation = uf::quaternion::multiply( transform.orientation, parsed.orientation ); + } else { + transform = uf::transform::decode( tag["transform"], transform ); + if ( tag["transform"]["parent"].is() ) { + auto* parentPointer = uf::graph::find( graph, tag["transform"]["parent"].as() ); + if ( parentPointer ) { + auto& parentNode = *parentPointer; + // entity already exists, bind to its transform + if ( parentNode.entity && parentNode.entity->hasComponent>() ) { + auto& parentTransform = parentNode.entity->getComponent>(); + transform = uf::transform::reference( transform, parentTransform, tag["transform"]["reorient"].as() ); + transform.position = -transform.position; + // doesnt exist, bind to the node transform + } else { + transform = uf::transform::reference( transform, parentNode.transform, tag["transform"]["reorient"].as() ); } } } @@ -860,23 +836,23 @@ void uf::graph::process( pod::Graph& graph, int32_t index, uf::Object& parent ) uf::graph::initializeGraphics( graph, entity ); } - if ( !ext::json::isNull( graph.metadata["tags"][node.name] ) ) { - auto info = graph.metadata["tags"][node.name]["physics"]; - if ( !ext::json::isObject( info ) ) info = metadataJson["system"]["physics"]; - else metadataJson["system"]["physics"] = info; + { + auto phyziks = tag["physics"]; + if ( !ext::json::isObject( phyziks ) ) phyziks = metadataJson["system"]["physics"]; + else metadataJson["system"]["physics"] = phyziks; - if ( ext::json::isObject( info ) ) { - uf::stl::string type = info["type"].as(); + if ( ext::json::isObject( phyziks ) ) { + uf::stl::string type = phyziks["type"].as(); if ( type == "mesh" ) { auto& collider = entity.getComponent(); - collider.stats.mass = info["mass"].as(collider.stats.mass); - collider.stats.friction = info["friction"].as(collider.stats.friction); - collider.stats.restitution = info["restitution"].as(collider.stats.restitution); - collider.stats.inertia = uf::vector::decode( info["inertia"], collider.stats.inertia ); - collider.stats.gravity = uf::vector::decode( info["gravity"], collider.stats.gravity ); + collider.stats.mass = phyziks["mass"].as(collider.stats.mass); + collider.stats.friction = phyziks["friction"].as(collider.stats.friction); + collider.stats.restitution = phyziks["restitution"].as(collider.stats.restitution); + collider.stats.inertia = uf::vector::decode( phyziks["inertia"], collider.stats.inertia ); + collider.stats.gravity = uf::vector::decode( phyziks["gravity"], collider.stats.gravity ); - uf::physics::impl::create( entity.as(), mesh, !info["static"].as(true) ); + uf::physics::impl::create( entity.as(), mesh, !phyziks["static"].as(true) ); } else { auto min = uf::matrix::multiply( model, bounds.min, 1.0f ); auto max = uf::matrix::multiply( model, bounds.max, 1.0f ); diff --git a/engine/src/engine/object/object.cpp b/engine/src/engine/object/object.cpp index c4b3b407..9a79a37c 100644 --- a/engine/src/engine/object/object.cpp +++ b/engine/src/engine/object/object.cpp @@ -10,10 +10,14 @@ #include #include -uf::Timer uf::Object::timer(false); +/* namespace { uf::Object null; } +*/ + +uf::Timer uf::Object::timer(false); +bool uf::Object::assertionLoad = true; UF_OBJECT_REGISTER_BEGIN(uf::Object) UF_OBJECT_REGISTER_BEHAVIOR(uf::EntityBehavior) @@ -432,7 +436,14 @@ uf::Object& uf::Object::loadChild( const uf::stl::string& f, bool initialize ) { uf::Serializer json; uf::stl::string filename = uf::io::resolveURI( f, metadata.system.root ); if ( !json.readFromFile(filename) ) { - return ::null; + if ( !uf::Object::assertionLoad ) { + UF_MSG_ERROR("assertionLoad is unset, loading empty entity"); + auto& entity = uf::instantiator::instantiate("Object"); + entity.getComponent().system.invalid = true; + this->addChild(entity); + } else { + UF_EXCEPTION("Failed to load file: " << filename); + } } json["source"] = filename; @@ -445,33 +456,39 @@ uf::Object& uf::Object::loadChild( const uf::Serializer& _json, bool initialize uf::Serializer json = _json; uf::stl::string type = json["type"].as(); if ( type == "" ) type = "Object"; - if ( json["ignore"].as() ) return ::null; uf::Entity& entity = uf::instantiator::instantiate(type); uf::Object& object = entity.as(); this->addChild(entity); + if ( json["ignore"].as() ) return object; if ( !object.load(json) ) { - this->removeChild(entity); - return ::null; + if ( !uf::Object::assertionLoad ) { + UF_MSG_ERROR("assertionLoad is unset, loading empty entity"); + entity.getComponent().system.invalid = true; + } else { + UF_EXCEPTION("Failed to load JSON: " << json); + } } if ( initialize ) entity.initialize(); return object; } uf::Object* uf::Object::loadChildPointer( const uf::stl::string& f, bool initialize ) { uf::Object* pointer = &this->loadChild(f, initialize); - return pointer != &::null ? pointer : NULL; + return pointer; +// return pointer != &::null ? pointer : NULL; } uf::Object* uf::Object::loadChildPointer( const uf::Serializer& json, bool initialize ) { uf::Object* pointer = &this->loadChild(json, initialize); - return pointer != &::null ? pointer : NULL; + return pointer; +// return pointer != &::null ? pointer : NULL; } -std::size_t uf::Object::loadChildUid( const uf::stl::string& f, bool initialize ) { +size_t uf::Object::loadChildUid( const uf::stl::string& f, bool initialize ) { uf::Object* pointer = this->loadChildPointer(f, initialize); - return pointer ? pointer->getUid() : -1; + return pointer ? pointer->getUid() : 0; } -std::size_t uf::Object::loadChildUid( const uf::Serializer& json, bool initialize ) { +size_t uf::Object::loadChildUid( const uf::Serializer& json, bool initialize ) { uf::Object* pointer = this->loadChildPointer(json, initialize); - return pointer ? pointer->getUid() : -1; + return pointer ? pointer->getUid() : 0; } uf::stl::string uf::Object::grabURI( const uf::stl::string& filename, const uf::stl::string& root ) { diff --git a/engine/src/ext/gltf/gltf.cpp b/engine/src/ext/gltf/gltf.cpp index 901d85db..2d5ed074 100644 --- a/engine/src/ext/gltf/gltf.cpp +++ b/engine/src/ext/gltf/gltf.cpp @@ -243,17 +243,15 @@ pod::Graph ext::gltf::load( const uf::stl::string& filename, const uf::Serialize bool print = false; bool cleanup = true; } meshgrid; - - if ( ext::json::isObject( graph.metadata["grid"][m.name] ) ) { - meshgrid.metadata = graph.metadata["grid"][m.name]; - } else { - ext::json::forEach( graph.metadata["grid"], [&]( const uf::stl::string& key, ext::json::Value& value ) { - if ( !ext::json::isNull( meshgrid.metadata["size"] ) ) return; - if ( !uf::string::isRegex( key ) ) return; + + ext::json::forEach( graph.metadata["tags"], [&]( const uf::stl::string& key, ext::json::Value& value ) { + if ( !ext::json::isObject( value["grid"] ) ) return; // no tag["grid"] defined + if ( ext::json::isNull( value["grid"]["size"] ) ) return; // no tag["grid"]["size"] defined + if ( uf::string::isRegex( key ) ) { if ( uf::string::matches( m.name, key ).empty() ) return; - meshgrid.metadata = value; - }); - } + } else if ( m.name != key ) return; + meshgrid.metadata = value["grid"]; + }); if ( ext::json::isObject( meshgrid.metadata ) ) { if ( meshgrid.metadata["size"].is() ) { @@ -267,6 +265,7 @@ pod::Graph ext::gltf::load( const uf::stl::string& filename, const uf::Serialize meshgrid.print = meshgrid.metadata["print"].as(meshgrid.print); meshgrid.cleanup = meshgrid.metadata["cleanup"].as(meshgrid.cleanup); } + if ( graph.metadata["flags"]["SKINNED"].as() ) { #define UF_GRAPH_MESH_FORMAT uf::graph::mesh::Skinned, uint32_t @@ -505,7 +504,7 @@ pod::Graph ext::gltf::load( const uf::stl::string& filename, const uf::Serialize } // generate STs #if UF_USE_XATLAS - { + if ( graph.metadata["exporter"]["unwrap"].as() ) { UF_MSG_DEBUG( "Generating ST's..." ); size_t atlases = ext::xatlas::unwrap( graph ); UF_MSG_DEBUG( "Generated ST's for " << atlases << " lightmaps" ); @@ -514,6 +513,10 @@ pod::Graph ext::gltf::load( const uf::stl::string& filename, const uf::Serialize if ( graph.metadata["exporter"]["enabled"].as() ) { uf::graph::save( graph, filename ); + // disable baking, doesn't output right if baking from a gltf imported model + graph.metadata["baking"]["enabled"] = false; + // disable lightmap loading, 99.999% of the time a previously baked lightmap will not work due to changing STs + graph.metadata["lightmap"] = false; } return graph; } diff --git a/engine/src/ext/gltf/processPrimitives2.inl b/engine/src/ext/gltf/processPrimitives2.inl index af1fe4c6..c708a312 100644 --- a/engine/src/ext/gltf/processPrimitives2.inl +++ b/engine/src/ext/gltf/processPrimitives2.inl @@ -155,6 +155,8 @@ for ( auto& p : m.primitives ) { #undef COPY_INDICES } + + meshlet.primitive.instance.materialID = p.material; meshlet.primitive.instance.primitiveID = meshlets.size() - 1; meshlet.primitive.instance.meshID = meshID; @@ -195,8 +197,7 @@ if ( meshgrid.grid.divisions.x > 1 && meshgrid.grid.divisions.y > 1 && meshgrid. .materialID = meshlet.primitive.drawCommand.materialID, .vertices = meshlet.vertices.size(), }); - //UF_MSG_DEBUG( ); - + primitives.emplace_back( meshlet.primitive ); indexID += meshlet.indices.size(); diff --git a/engine/src/ext/xatlas/xatlas.cpp b/engine/src/ext/xatlas/xatlas.cpp index 6d8346a6..c3fad58b 100644 --- a/engine/src/ext/xatlas/xatlas.cpp +++ b/engine/src/ext/xatlas/xatlas.cpp @@ -2,6 +2,9 @@ #if UF_USE_XATLAS #include +#define UF_XATLAS_UNWRAP_MULTITHREAD 1 +#define UF_XATLAS_LAZY 1 // i do not understand why it needs to insert extra vertices for it to not even be used in the indices buffer, this flag avoids having to account for it + size_t UF_API ext::xatlas::unwrap( pod::Graph& graph, bool combined ) { struct Entry { size_t index = 0; @@ -134,15 +137,37 @@ size_t UF_API ext::xatlas::unwrap( pod::Graph& graph, bool combined ) { packOptions.bilinear = true; // pack + pod::Thread::container_t jobs; + + for ( auto& pair : atlases ) { + jobs.emplace_back([&]{ + auto& atlas = pair.second; + ::xatlas::Generate(atlas.pointer, chartOptions, packOptions); + /* + // get vertices size ahead of time + for ( auto i = 0; i < atlas.pointer->meshCount; ++i ) { + auto& xmesh = atlas.pointer->meshes[i]; + auto& entry = atlas.entries[i]; + // atlas.vertices += xmesh.vertexCount; + sizes[entry.index] += xmesh.vertexCount; + } + */ + }); + } + +#if UF_XATLAS_UNWRAP_MULTITHREAD + if ( !jobs.empty() ) uf::thread::batchWorkers_Async( jobs ); +#else + for ( auto& job : jobs ) job(); +#endif + +#if !UF_XATLAS_LAZY for ( auto& pair : atlases ) { auto& atlas = pair.second; - ::xatlas::Generate(atlas.pointer, chartOptions, packOptions); - // get vertices size ahead of time for ( auto i = 0; i < atlas.pointer->meshCount; ++i ) { auto& xmesh = atlas.pointer->meshes[i]; auto& entry = atlas.entries[i]; - // atlas.vertices += xmesh.vertexCount; sizes[entry.index] += xmesh.vertexCount; } } @@ -151,13 +176,16 @@ size_t UF_API ext::xatlas::unwrap( pod::Graph& graph, bool combined ) { for ( auto i = 0; i < graph.meshes.size(); ++i ) { auto& name = graph.meshes[i]; auto& mesh = /*graph.storage*/uf::graph::storage.meshes[name]; - - mesh.resizeVertices( sizes[i] ); - mesh.updateDescriptor(); + if ( sizes[i] != mesh.vertex.count ) { + mesh.resizeVertices( sizes[i] ); + mesh.updateDescriptor(); + } } +#endif // update vertices for ( auto& pair : atlases ) { + size_t vertexIDOffset = 0; auto& atlas = pair.second; for ( auto i = 0; i < atlas.pointer->meshCount; i++ ) { auto& xmesh = atlas.pointer->meshes[i]; @@ -166,32 +194,47 @@ size_t UF_API ext::xatlas::unwrap( pod::Graph& graph, bool combined ) { auto& mesh = /*graph.storage*/uf::graph::storage.meshes[name]; auto& source = sources[entry.index]; + // draw commands if ( mesh.indirect.count ) { - // vertices auto srcInput = source.remapVertexInput( entry.commandID ); auto dstInput = mesh.remapVertexInput( entry.commandID ); - auto vertexCount = xmesh.vertexCount; + #if UF_XATLAS_LAZY + for ( auto j = 0; j < xmesh.vertexCount; ++j ) { + auto& vertex = xmesh.vertexArray[j]; + auto ref = vertex.xref; + + for ( auto k = 0; k < srcInput.attributes.size(); ++k ) { + auto dstAttribute = dstInput.attributes[k]; + if ( dstAttribute.descriptor.name != "st" ) continue; + pod::Vector2f& st = *(pod::Vector2f*) ( static_cast(dstAttribute.pointer) + dstAttribute.stride * (ref + dstInput.first) ); + st = pod::Vector2f{ vertex.uv[0] / atlas.pointer->width, vertex.uv[1] / atlas.pointer->height };; + } + } + #else auto& primitives = /*graph.storage*/uf::graph::storage.primitives[name]; pod::DrawCommand* drawCommands = (pod::DrawCommand*) mesh.getBuffer(mesh.indirect).data(); - drawCommands[entry.commandID].vertices = vertexCount; - primitives[entry.commandID].drawCommand.vertices = vertexCount; + bool mismatched = xmesh.vertexCount != drawCommands[entry.commandID].vertices; + vertexIDOffset += xmesh.vertexCount - drawCommands[entry.commandID].vertices; + + drawCommands[entry.commandID].vertices = xmesh.vertexCount; + primitives[entry.commandID].drawCommand.vertices = xmesh.vertexCount; + drawCommands[entry.commandID].vertexID += vertexIDOffset; + primitives[entry.commandID].drawCommand.vertexID += vertexIDOffset; for ( auto j = 0; j < xmesh.vertexCount; ++j ) { auto& vertex = xmesh.vertexArray[j]; auto ref = vertex.xref; - for ( auto k = 0; k < mesh.vertex.attributes.size(); ++k ) { - // auto srcAttribute = source.remapVertexAttribute( source.vertex.attributes[k], entry.commandID ); - // auto dstAttribute = mesh.remapVertexAttribute( mesh.vertex.attributes[k], entry.commandID ); - - auto srcAttribute = source.vertex.attributes[k]; - auto dstAttribute = mesh.vertex.attributes[k]; + + for ( auto k = 0; k < srcInput.attributes.size(); ++k ) { + auto srcAttribute = srcInput.attributes[k]; + auto dstAttribute = dstInput.attributes[k]; if ( dstAttribute.descriptor.name == "st" ) { pod::Vector2f& st = *(pod::Vector2f*) ( static_cast(dstAttribute.pointer) + dstAttribute.stride * (j + dstInput.first) ); - st = pod::Vector2f{ vertex.uv[0] / atlas.pointer->width, vertex.uv[1] / atlas.pointer->height }; + st = pod::Vector2f{ vertex.uv[0] / atlas.pointer->width, vertex.uv[1] / atlas.pointer->height };; } else { memcpy( static_cast(dstAttribute.pointer) + dstAttribute.stride * (j + dstInput.first), static_cast(srcAttribute.pointer) + srcAttribute.stride * (ref + srcInput.first), srcAttribute.stride ); } @@ -211,12 +254,29 @@ size_t UF_API ext::xatlas::unwrap( pod::Graph& graph, bool combined ) { } } } + #endif } else { uf::Mesh::Attribute stAttribute; for ( auto& attribute : mesh.vertex.attributes ) if ( attribute.descriptor.name == "st" ) stAttribute = attribute; UF_ASSERT( stAttribute.descriptor.name == "st" ); // vertices + #if UF_XATLAS_LAZY + auto srcInput = source.vertex; + auto dstInput = mesh.vertex; + + for ( auto j = 0; j < xmesh.vertexCount; ++j ) { + auto& vertex = xmesh.vertexArray[j]; + auto ref = vertex.xref; + + for ( auto k = 0; k < srcInput.attributes.size(); ++k ) { + auto dstAttribute = dstInput.attributes[k]; + if ( dstAttribute.descriptor.name != "st" ) continue; + pod::Vector2f& st = *(pod::Vector2f*) ( static_cast(dstAttribute.pointer) + dstAttribute.stride * (ref + dstInput.first) ); + st = pod::Vector2f{ vertex.uv[0] / atlas.pointer->width, vertex.uv[1] / atlas.pointer->height };; + } + } + #else for ( auto j = 0; j < xmesh.vertexCount; ++j ) { auto& vertex = xmesh.vertexArray[j]; auto ref = vertex.xref; @@ -265,12 +325,13 @@ size_t UF_API ext::xatlas::unwrap( pod::Graph& graph, bool combined ) { } } } + #endif } - mesh.updateDescriptor(); } } +#if !UF_XATLAS_LAZY // update vertexID offsets for indirect commands for ( auto index = 0; index < graph.meshes.size(); ++index ) { auto& name = graph.meshes[index]; @@ -281,6 +342,7 @@ size_t UF_API ext::xatlas::unwrap( pod::Graph& graph, bool combined ) { auto& primitives = /*graph.storage*/uf::graph::storage.primitives[name]; pod::DrawCommand* drawCommands = (pod::DrawCommand*) mesh.getBuffer(mesh.indirect).data(); + size_t vertexID = 0; for ( auto i = 0; i < mesh.indirect.count; ++i ) { auto& primitive = primitives[i]; @@ -292,6 +354,7 @@ size_t UF_API ext::xatlas::unwrap( pod::Graph& graph, bool combined ) { vertexID += drawCommand.vertices; } } +#endif // cleanup size_t atlasCount = 0; diff --git a/engine/src/ext/xatlas/xatlas_src.cpp b/engine/src/ext/xatlas/xatlas_src.cpp index f72d6bea..155f4c2a 100644 --- a/engine/src/ext/xatlas/xatlas_src.cpp +++ b/engine/src/ext/xatlas/xatlas_src.cpp @@ -4295,8 +4295,8 @@ static NLMatrix nlCRSMatrixNewFromSparseMatrix(NLSparseMatrix* M) CRS->sliceptr[0] = 0; for (slice = 1; slice < nslices; ++slice) { while (cur_NNZ < cur_bound && cur_row < M->m) { - ++cur_row; cur_NNZ += CRS->rowptr[cur_row + 1] - CRS->rowptr[cur_row]; + ++cur_row; } CRS->sliceptr[slice] = cur_row; cur_bound += slice_size; @@ -4754,13 +4754,10 @@ public: Vector2 *v = m_vertexBuffers[m_activeVertexBuffer]; v[m_numVertices] = v[0]; m_area = 0; - float centroidx = 0, centroidy = 0; for (uint32_t k = 0; k < m_numVertices; k++) { // http://local.wasp.uwa.edu.au/~pbourke/geometry/polyarea/ float f = v[k].x * v[k + 1].y - v[k + 1].x * v[k].y; m_area += f; - centroidx += f * (v[k].x + v[k + 1].x); - centroidy += f * (v[k].y + v[k + 1].y); } m_area = 0.5f * fabsf(m_area); } @@ -9090,7 +9087,6 @@ AddMeshError AddMesh(Atlas *atlas, const MeshDecl &meshDecl, uint32_t meshCountH const uint32_t kMaxWarnings = 50; uint32_t warningCount = 0; internal::Array triIndices; - uint32_t firstFaceIndex = 0; internal::Triangulator triangulator; for (uint32_t face = 0; face < faceCount; face++) { // Decode face indices. @@ -9200,7 +9196,6 @@ AddMeshError AddMesh(Atlas *atlas, const MeshDecl &meshDecl, uint32_t meshCountH for (uint32_t i = 0; i < triIndices.size(); i++) meshPolygonMapping->triangleToPolygonIndicesMap.push_back(triIndices[i]); } - firstFaceIndex += faceVertexCount; } if (warningCount > kMaxWarnings) XA_PRINT(" %u additional warnings truncated\n", warningCount - kMaxWarnings); diff --git a/engine/src/utils/thread/thread.cpp b/engine/src/utils/thread/thread.cpp index d59d162b..093a8eed 100644 --- a/engine/src/utils/thread/thread.cpp +++ b/engine/src/utils/thread/thread.cpp @@ -66,14 +66,6 @@ void UF_API uf::thread::batchWorker( const pod::Thread::function_t& function, co return batchWorkers( { function }, false, name ); } void UF_API uf::thread::batchWorkers( const uf::stl::vector& functions, bool wait, const uf::stl::string& name ) { - if ( uf::thread::async ) { - uf::stl::vector> futures; - futures.reserve(functions.size()); - for ( auto& function : functions ) futures.emplace_back(std::async( std::launch::async, function )); - if ( wait ) for ( auto& future : futures ) future.wait(); - return; - } - uf::stl::vector workers; for ( auto& function : functions ) { auto& worker = uf::thread::fetchWorker( name ); @@ -82,6 +74,14 @@ void UF_API uf::thread::batchWorkers( const uf::stl::vector& functions, bool wait, const uf::stl::string& name ) { +// if ( uf::thread::async ) + uf::stl::vector> futures; + futures.reserve(functions.size()); + for ( auto& function : functions ) futures.emplace_back(std::async( std::launch::async, function )); + if ( wait ) for ( auto& future : futures ) future.wait(); + return; +} void UF_API uf::thread::add( pod::Thread& thread, const pod::Thread::function_t& function, bool temporary ) { if ( thread.mutex != NULL ) thread.mutex->lock(); temporary ? thread.temps.push( function ) : thread.consts.push_back( function ); diff --git a/ext/behaviors/baking/behavior.cpp b/ext/behaviors/baking/behavior.cpp index 80ea207d..5b76716b 100644 --- a/ext/behaviors/baking/behavior.cpp +++ b/ext/behaviors/baking/behavior.cpp @@ -15,6 +15,8 @@ #include "../light/behavior.h" #include "../scene/behavior.h" +#define UF_BAKER_SAVE_MULTITHREAD 1 + UF_BEHAVIOR_REGISTER_CPP(ext::BakingBehavior) UF_BEHAVIOR_TRAITS_CPP(ext::BakingBehavior, ticks = true, renders = false, multithread = false) #define this (&self) @@ -39,14 +41,15 @@ void ext::BakingBehavior::initialize( uf::Object& self ) { metadata.output = this->grabURI( metadataJson["baking"]["output"].as(), metadataJson["baking"]["root"].as() ); metadata.renderModeName = "B:" + std::to_string((int) this->getUid()); - metadata.trigger.mode = metadataJson["baking"]["trigger"]["mode"].as(); - metadata.trigger.value = metadataJson["baking"]["trigger"]["value"].as(); + metadata.trigger.mode = metadataJson["baking"]["trigger"]["mode"].as( metadata.trigger.mode ); + metadata.trigger.value = metadataJson["baking"]["trigger"]["value"].as( metadata.trigger.value ); + metadata.trigger.quits = metadataJson["baking"]["trigger"]["quits"].as( metadata.trigger.quits ); if ( metadataJson["baking"]["resolution"].is() ) metadata.size = { metadataJson["baking"]["resolution"].as(), metadataJson["baking"]["resolution"].as() }; metadata.max.shadows = metadataJson["baking"]["shadows"].as(metadata.max.shadows); - metadata.max.layers = metadataJson["baking"]["layers"].as(metadata.max.layers); + metadata.max.layers = std::max( metadataJson["baking"]["layers"].as(metadata.max.layers), (size_t) 1 ); metadata.cull = metadataJson["baking"]["cull"].as(); @@ -113,20 +116,30 @@ PREPARE: { renderMode.setTarget(""); uf::renderer::states::rebuild = true; - UF_MSG_DEBUG("Graphic configured, ready to bake"); + UF_MSG_DEBUG("Graphic configured, ready to bake " << metadata.max.layers << " lightmaps"); return; } SAVE: { #if 1 renderMode.execute = false; UF_MSG_DEBUG("Baking..."); + + pod::Thread::container_t jobs; + for ( size_t i = 0; i < metadata.max.layers; ++i ) { - // auto image = renderMode.screenshot(0, i); - auto image = metadata.buffers.baked.screenshot(i); - uf::stl::string filename = uf::string::replace( metadata.output, "%i", std::to_string(i) ); - bool status = image.save(filename); - UF_MSG_DEBUG("Writing to " << filename << ": " << status); + jobs.emplace_back([&, i]{ + // auto image = renderMode.screenshot(0, i); + auto image = metadata.buffers.baked.screenshot(i); + uf::stl::string filename = uf::string::replace( metadata.output, "%i", std::to_string(i) ); + bool status = image.save(filename); + UF_MSG_DEBUG("Writing to " << filename << ": " << status); + }); } +#if UF_BAKER_SAVE_MULTITHREAD + if ( !jobs.empty() ) uf::thread::batchWorkers_Async( jobs ); +#else + for ( auto& job : jobs ) job(); +#endif UF_MSG_DEBUG("Baked."); metadata.initialized.map = true; @@ -142,6 +155,8 @@ SAVE: { ext::json::Value payload; payload["uid"] = this->getUid(); uf::scene::getCurrentScene().queueHook("system:Destroy", payload); + + if ( metadata.trigger.quits ) uf::scene::getCurrentScene().queueHook("system:Quit", payload); #endif return; } diff --git a/ext/behaviors/baking/behavior.h b/ext/behaviors/baking/behavior.h index 842146da..6a228fab 100644 --- a/ext/behaviors/baking/behavior.h +++ b/ext/behaviors/baking/behavior.h @@ -5,6 +5,7 @@ #include #include #include +#include namespace ext { namespace BakingBehavior { @@ -39,8 +40,9 @@ namespace ext { size_t update = 0; } previous; struct { - uf::stl::string mode = "key"; + uf::stl::string mode = "rendered"; uf::stl::string value = ""; + bool quits = true; } trigger; struct { bool renderMode = false; diff --git a/ext/main.cpp b/ext/main.cpp index e897e1c2..4d386a57 100644 --- a/ext/main.cpp +++ b/ext/main.cpp @@ -214,6 +214,9 @@ void EXT_API ext::initialize() { { uf::Entity::deleteChildrenOnDestroy = ::json["engine"]["debug"]["entity"]["delete children on destroy"].as( uf::Entity::deleteChildrenOnDestroy ); uf::Entity::deleteComponentsOnDestroy = ::json["engine"]["debug"]["entity"]["delete components on destroy"].as( uf::Entity::deleteComponentsOnDestroy ); + + uf::Object::assertionLoad = ::json["engine"]["debug"]["loader"]["assert"].as( uf::Object::assertionLoad ); + uf::Asset::assertionLoad = ::json["engine"]["debug"]["loader"]["assert"].as( uf::Asset::assertionLoad ); } {