Commit for 2023.02.04 22-48-51.7z

This commit is contained in:
mrq 2023-02-04 22:48:00 -06:00
parent fa1e54c7f7
commit 1c8721f615
72 changed files with 4293 additions and 0 deletions

397
bin/data/config.json Normal file
View File

@ -0,0 +1,397 @@
{
"engine": {
"scenes": {
"start": "SourceEngine",
"matrix": { "reverseInfinite": true },
"meshes": { "interleaved": false },
"lights": { "enabled": true,
"useLightmaps": true,
"max": 32,
"shadows": {
"enabled": true,
"update": 4,
"max": 8,
"samples": 4
},
"bloom": {
"scale": 1.0,
"strength": 0.125,
"sigma": 0.8,
"samples": 5,
"threshold": 1.0
}
},
"textures": {
"max": {
"2D": 1024,
"cube": 1024,
"3D": 128
}
},
"vxgi": {
"limiter": 0.125,
// "limiter": 0.125,
"size": 192,
"dispatch": 8,
"cascades": 3,
"cascadePower": 1.5,
"granularity": 12,
"voxelizeScale": 1,
"occlusionFalloff": 2,
"traceStartOffsetFactor": 1,
"shadows": 0,
"extents": {
"min": [ -4, -4, -4 ],
"max": [ 4, 4, 4 ]
}
},
"rt": {
// "size": [ 1280, 720 ],
"full": false,
"filter": "nearest",
"defaultRayBounds": [ 0.75, 256.0 ],
"alphaTestOffset": 0.05,
"samples": 1,
"paths": 2,
"frameAccumulationMinimum": 0,
"readyTimer": 3
}
},
"graph": {
"initial buffer elements": 1024
},
"ext": {
"vulkan": {
"version": 1.3,
"validation": {
"enabled": false,
"messages": false,
"checkpoints": false,
"filters": [
"0x71500fba" // VUID-vkDestroyDevice-device-00378 (don't care about a clean cleanup)
,"0xe5d1743c" // VUID-vkCmdDispatch-None-02699 (problem when using VXGI)
// ,"0x141cb623" // UNASSIGNED-Threading-MultipleThreads ("false-positive" multithreading)
/*
"0x609a13b" // UNASSIGNED-CoreValidation-Shader-OutputNotConsumed (from depth-only calls)
,"0x35d7ea98" // VUID-vkUpdateDescriptorSets-None-03047 (bitches without VK_DESCRIPTOR_BINDING_UPDATE_AFTER_BIND_BIT or VK_DESCRIPTOR_BINDING_UPDATE_UNUSED_WHILE_PENDING_BIT)
,"0x8e1000ad" // VUID-vkCmdDrawIndexedIndirect-None-04008 (bitches without nullDescriptor)
,"0x9dd97212" // VUID-vkCmdDrawIndexedIndirect-None-02721 (bitches without nullDescriptor)
,"0x36481fcb" // VUID-vkCmdBindVertexBuffers-pBuffers-04001 (bitches without nullDescriptor)
*/
// ,"0x4dae5635" // UNASSIGNED-CoreValidation-DrawState-InvalidImageLayout
]
},
"framebuffer": {
"msaa": 1,
"size": 1
// "size": [ 640, 480, "NEAREST" ]
// "size": [ 1280, 720 ]
// "size": [ 960, 540 ]
// "size": [ 640, 480 ]
},
"gpu": 7817, // 2060
// "gpu": 29631, // 6800XT
"experimental": {
"rebuild on tick begin": false,
"batch queue submissions": true,
"dedicated thread": false,
"memory budget": false
},
"invariant": {
"default stage buffers": true,
"default defer buffer destroy": true,
"default command buffer immediate": true,
"multithreaded recording": true
},
"pipelines": {
"deferred": true,
"vsync": true,
"hdr": true,
"vxgi": true,
"culling": true,
"bloom": true,
"rt": false,
"fsr": false,
"postProcess": false // "postProcess.chromab" // false
},
"formats": {
"depth": "D32_SFLOAT",
"color": "R16G16B16A16_SFLOAT", // "R32G32B32A32_SFLOAT",
"normal": "R16G16B16A16_SFLOAT",
"position": "R16G16B16A16_SFLOAT"
},
"versions": {
"1.0": {
"extensions": {
"instance": [],
"device": [
"VK_KHR_swapchain"
]
},
"features": [
"shaderDrawParameters",
"multiDrawIndirect",
"fillModeNonSolid",
"wideLines",
"independentBlend",
"deviceCoherentMemory",
"robustBufferAccess",
"samplerAnisotropy",
"sampleRateShading"
],
"featureChain": []
},
"1.1": {
"extensions": {
"instance": [
"VK_KHR_get_physical_device_properties2"
,"VK_KHR_get_surface_capabilities2"
],
"device": [
"VK_EXT_memory_budget"
,"VK_EXT_descriptor_indexing"
,"VK_KHR_buffer_device_address"
,"VK_NV_device_diagnostic_checkpoints"
]
},
"features": [
"nullDescriptor"
,"fragmentStoresAndAtomics"
,"geometryShader"
,"multiViewport"
,"shaderInt16"
,"shaderFloat16"
,"shaderInt64"
,"shaderFloat64"
,"shaderSubgroupClock"
,"shaderSampledImageArrayDynamicIndexing"
,"shaderStorageImageArrayDynamicIndexing"
,"shaderStorageImageMultisample"
,"shaderSampledImageArrayNonUniformIndexing"
,"shaderStorageImageArrayNonUniformIndexing"
,"descriptorIndexing"
,"bufferDeviceAddress"
],
"featureChain": [
"physicalDevice2"
,"shaderDrawParameters"
,"robustness"
,"shaderClock"
,"descriptorIndexing"
,"bufferDeviceAddress"
]
},
"1.2": {
"extensions": {
"instance": [
"VK_KHR_get_physical_device_properties2",
"VK_KHR_get_surface_capabilities2"
],
"device": [
"VK_KHR_deferred_host_operations"
,"VK_EXT_shader_viewport_index_layer"
,"VK_KHR_spirv_1_4"
,"VK_KHR_shader_float_controls"
,"VK_KHR_shader_clock"
,"VK_EXT_subgroup_size_control"
,"VK_KHR_acceleration_structure"
,"VK_KHR_ray_tracing_pipeline"
,"VK_KHR_ray_query"
// ,"VK_AMD_shader_explicit_vertex_parameter"
// ,"VK_KHR_fragment_shader_barycentric"
]
},
"features": [
"hostQueryReset",
"runtimeDescriptorArray",
"descriptorBindingVariableDescriptorCount",
"shaderOutputViewportIndex",
"shaderOutputLayer"
],
"featureChain": [
"physicalDeviceVulkan12"
// for advanced gbuffer
,"fragmentShaderBarycentric"
// for ray-tracing
,"rayTracingPipeline"
,"rayQuery"
,"accelerationStructure"
// for FSR2
,"subgroupSizeControl"
]
},
"1.3": {
"extensions": {
"instance": [],
"device": []
},
"features": [],
"featureChain": []
}
}
},
"opengl": {
"validation": { "enabled": false },
"framebuffer": { "size": 1, "msaa": 1 },
"experimental": {
"rebuild on tick begin": true
},
"pipelines": {
"culling": true
},
"experimental": {
"rebuild on tick begin": true
},
"invariant": {
"multithreaded recording": false
},
"formats": {
"depth": "D32_SFLOAT",
"color": "R8G8B8A8_UNORM", // "R32G32B32A32_SFLOAT",
"normal": "R16G16B16A16_SFLOAT",
"position": "R16G16B16A16_SFLOAT"
},
"features": [],
"extensions": { "instance": [], "device": [] }
},
"lua": {
"enabled": true,
"main": "/main.lua",
"modules": {
"json": "/json.lua"
}
},
"json": {
"encoding": "msgpack",
"compression": "gz"
},
"imgui": {
"enabled": true
},
"fsr": {
"enabled": true,
"sharpness": 1,
"jitter scale": 0.0625,
"preset": "native" // native (1x), quality (1.5x), balanced (1.7x), performance (2.0x), ultra (3.0x)
},
"reactphysics": {
"timescale": 0.01666666666,
"interpolate": false,
"gravity": {
"mode": "universal",
"constant": 6.67408e-11
},
"debug draw": {
"enabled": false,
"line width": 8,
// "layer": "Gui",
"rate": 0.0125
}
},
"vr" : {
"enable" : false,
"manifest": "./data/openvr_manifest.json",
"swap eyes": false,
"dominant eye": 0,
"scale": 1.0
},
"ultralight": { "enabled": true, "scale": 1.5 },
"discord": { "enabled": false }
},
"audio": {
"mute": false,
"buffers": {
"size": 32768,
"count": 4
},
"volumes": {
"sfx": 0.35,
"bgm": 0.15,
"voice": 1.0
},
"streams by default": true
},
"memory pool": {
"enabled": true,
"subPools": true,
"alignment": 64,
"override": false,
"size": "512 MiB",
"pools": {
"entity": "128 MiB",
"userdata": "128 MiB",
"component": "128 MiB"
}
},
"render modes": { "gui": true, "deferred": true },
"limiters": {
"deltaTime": 5,
"framerate": "auto"
},
"threads": {
"workers" : "auto",
"frame limiter": 0 // "auto"
},
"debug": {
"framerate": {
"print": true,
"every": 2
},
"garbage collection": {
"enabled": true,
"mode": 1,
"rate": 4,
"announce": true
},
"entity": {
"delete children on destroy": false,
"delete components on destroy": false
},
"userdata": {
"auto destruct": true,
"auto validate": false
},
"loader": {
"assert": true
},
"hooks": {
"defer lazy calls": true
},
"scene": {
"print task calls": false
}
}
},
"window" : {
"terminal" : {
"ncurses" : false,
"visible" : true
},
"keyboard" : {
"repeat" : false
},
"mouse" : {
"visible" : true,
"center" : false,
"sensitivity": [ 2, 2 ],
"smoothing": [ 4, 4 ]
},
"mode" : "windowed", // fullscreen, borderless, windowed
"icon" : "./data/textures/icon.png",
// "size" : [ 1920, 1080 ],
"size" : [ 1280, 720 ],
// "size" : [ 960, 540 ],
// "size" : [ 640, 480 ],
// "size" : [ 256, 224 ],
"title" : "Grimgram",
"visible" : true
}
}

View File

@ -0,0 +1,55 @@
{
"type": "Object",
"name": "Burger",
"ignore": false,
"import": "/model.json",
"assets": [
// "/burger/burger.glb"
// "/burger/burger_simpler.glb"
// "/burger/burger/graph.json"
"/burger/burger_simpler/graph.json"
],
"behaviors": [],
"transform": {
"position": [ -0.574743, 2.3547, -5.05161 ],
// "position": [ -4.66561, 0.0736207, -5.98057 ],
"rotation": {
"axis": [ 0, 1, 0 ],
"angle": 0
},
"scale": [ 1, 1, 1 ]
},
"system": {
"hot reload": {
"enabled": true
}
},
"metadata": {
"holdable": true,
"physics": {
"gravity": [ 0, -9.81, 0 ],
"inertia": [ 0, 0, 0 ],
"mass": 10,
"type": "bounding box",
"recenter": false
},
"graph": {
"exporter": {
"enabled": true,
"unwrap": false,
"optimize": false
},
"baking": {
"enabled": false
},
"renderer": {
"flip textures": false
},
"lighting": {
"lightmap": false
}
}
}
}

View File

@ -0,0 +1,39 @@
{
"type": "Object",
"name": "Cornell Box",
"ignore": false,
"import": "/model.json",
"assets": [
// "/cornell/cornell.glb"
{ "filename": "/cornell/cornell/graph.json" }
],
"behaviors": [],
"transform": {
"position": [ -0.23807, -0.984829, -30.4967 ],
"rotation": {
"axis": [ 0, 1, 0 ],
"angle": 0
},
"scale": [ 1, 1, 1 ]
},
"system": {
"hot reload": {
"enabled": true
}
},
"metadata": {
"track": true,
"hide": true,
"graph": {
"lightmap": false,
"exporter": {
"enabled": false,
"unwrap": false,
"optimize": false
},
"baking": {
"enabled": false
}
}
}
}

View File

@ -0,0 +1,14 @@
{
"assets": ["./scripts/door.lua"],
"behaviors": [
"SoundEmitterBehavior"
],
"metadata": {
"physics": {
"mass": 0,
"inertia": [0, 0, 0],
"type": "bounding box",
"recenter": true
}
}
}

View File

@ -0,0 +1,8 @@
{
"name": "Gui Manager",
"type": "Object",
"behaviors": [
"GuiManagerBehavior"
],
"ignore": false
}

View File

@ -0,0 +1,20 @@
{
"name": "HUD",
"type": "Gui",
"ignore": false,
"assets": [
"./scripts/hud.lua"
],
"transform": {
"position": [ 0, 0, 0 ],
"rotation": {
"axis": [ 0, 0, 1 ],
"angle": 0
},
"scale": [ 16, 16, 16 ]
},
"metadata": {
"clickable": false,
"hoverable": false,
}
}

View File

@ -0,0 +1,35 @@
{
"name": "HUD Overlay",
"type": "Gui",
"ignore": false,
"assets": [
{ "filename": "./textures/mp.png", "hash": "68e7c459f9aecd6815ff7df1e2eefa82db60a23713b0134f0bfc15d82f55453d" }
// { "filename": "./textures/ss2.png" }
],
"transform": {
"position": [ 0, 0, 0 ],
"rotation": {
"axis": [ 0, 0, 1 ],
"angle": 0
},
// "scale": [ 1.7776, -1, -1 ]
"scale": [ 1, 1, 1 ]
},
"metadata": {
"clickable": false,
"hoverable": false,
"uv": [ 0, 0, 1, 1 ],
// "color": [ 0.8, 0.8, 1, 1 ],
// "color": [ 0.416, 0.573, 0.667, 1 ],
"color": [ 1, 1, 1, 1 ],
"location": "",
"scaling": "relative",
// "depth": 0.1,
// "alpha": 0.5,
"alpha": 0.75,
"mode": 1,
"gui layer": true,
"only model": true
}
}

View File

@ -0,0 +1,154 @@
local scene = entities.currentScene()
local controller = entities.controller()
local metadata = ent:getComponent("Metadata")
local masterdata = scene:getComponent("Metadata")
local visorLayers = 5
local children = {}
for i=1, visorLayers do
children[i] = ent:loadChild("./overlay.json",true)
end
local soundEmitter = ent:loadChild("./sound.json",true)
local timer = Timer.new()
if not timer:running() then timer:start() end
Static = {
values = {},
get = function( obj )
if obj == nil then
obj = scene
end
if Static.values[""..obj:uid()] == nil then
Static.values[""..obj:uid()] = {}
end
return Static.values[""..obj:uid()]
end
}
local lerper = {
to = Quaternion(0,0,0,1),
from = Quaternion(0,0,0,1),
a = 0
}
local rotate = function( delta )
delta.x = delta.x * 0.1
delta.y = delta.y * 0.1
local transform = ent:getComponent("Transform")
local rotation = {
x = Quaternion.axisAngle( Vector3f(0, 1, 0), delta.x ),
y = Quaternion.axisAngle( Vector3f(1, 0, 0), delta.y )
}
lerper.a = 0
lerper.from = Quaternion.multiply( transform.orientation, rotation.x:multiply(rotation.y) )
transform.orientation = lerper.from
for k, obj in pairs(children) do
obj:getComponent("Transform").orientation = transform.orientation
end
end
local windowSize = masterdata["system"]["config"]["window"]["size"];
local entTransform = ent:getComponent("Transform")
entTransform.scale.x = entTransform.scale.x * windowSize.x / windowSize.y;
for k, obj in pairs(children) do
local transform = obj:getComponent("Transform")
transform.scale = entTransform.scale;
transform.position.z = -0.5 + ((k-1) * 0.005)
end
ent:addHook( "window:Resized", function( payload )
if entTransform.scale.y == entTransform.scale.z then
entTransform.scale.x = entTransform.scale.y * payload["window"]["size"][1] / payload["window"]["size"][2];
end
for k, obj in pairs(children) do
local transform = obj:getComponent("Transform")
transform.scale = entTransform.scale;
end
end )
ent:addHook( "controller:Camera.Rotated", function( payload )
rotate( {
x = -payload.angle.yaw,
y = -payload.angle.pitch
})
--[[
local transform = ent:getComponent("Transform")
lerper.a = 0
local counterOrientation = Quaternion( payload.delta[1], payload.delta[2], payload.delta[3], payload.delta[4] ):inverse()
lerper.from = Quaternion.multiply( transform.orientation, counterOrientation )
transform.orientation = lerper.from
for k, obj in pairs(children) do
obj:getComponent("Transform").orientation = transform.orientation
end
]]
end )
--[[
ent:addHook( "window:Mouse.Moved", function( payload )
if payload.invoker ~= "client" then return end
local delta = payload.mouse.delta
local size = payload.mouse.size
if delta == nil or size == nil then return end
if delta.x == 0 or delta.y == 0 then return end
delta.x = -delta.x / size.x
delta.y = -delta.y / size.y
rotate( delta )
end )
]]
ent:bind( "tick", function(self)
for k, obj in pairs(children) do
local metadata = obj:getComponent("Metadata")
local glow = math.sin(time.current()) * 0.5 + 0.5 -- constrained to [0,1]
glow = glow * 0.2 + 0.65 -- constrained to [0.65, 0.85]
metadata["alpha"] = glow
obj:setComponent("Metadata", metadata)
end
local controllerTransform = controller:getComponent("Transform")
local controllerCamera = controller:getComponent("Camera")
local controllerCameraTransform = controllerCamera:getTransform()
local transform = ent:getComponent("Transform")
local speed = 2.5
if lerper.a == 1 then return end
lerper.a = lerper.a + time.delta() * speed
if lerper.a > 1 then lerper.a = 1 end
transform.orientation = lerper.from:slerp( lerper.to, lerper.a )
local orientation = transform.orientation
for k, obj in pairs(children) do
local transform = obj:getComponent("Transform")
transform.orientation = orientation
transform.model = controllerCamera:getProjection() * Matrix4f.translate( transform.position ) * transform.orientation:matrix() * Matrix4f.scale( transform.scale ) --Matrix4f.scale( Vector3f( 1.7776 * 2, 2, 2 ) )
end
end )
--[[
controller:callHook( "object:UpdateMetadata.%UID%", {
path = "overlay.position",
value = {
[1] = position.x,
[2] = position.y,
[3] = position.z
}
} )
controller:callHook( "object:UpdateMetadata.%UID%", {
path = "overlay.orientation",
value = {
[1] = orientation.x,
[2] = orientation.y,
[3] = orientation.z,
[4] = orientation.w
}
} )
]]

View File

@ -0,0 +1,38 @@
{
"type": "Object",
"name": "Sound Emitter",
"ignore": false,
"assets": [
],
"behaviors": [
"SoundEmitterBehavior"
],
"transform": {
"position": [ 0, 0, 0 ],
"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": false,
"loop": false,
"volume": "sfx",
"rolloffFactor": 2
}
}
}

View File

@ -0,0 +1,26 @@
{
"name": "Menu: Circle Inner",
"type": "Gui",
"ignore": false,
"transform": {
"position": [ 0.86, 0.86, 0 ],
"rotation": {
"axis": [ 1, 0, 0 ],
"angle": 0
},
"scale": [ 1, 1, 1 ]
},
"metadata": {
"clickable": false,
"hoverable": false,
"uv": [ 0, 0, 1, 1 ],
"color": [ 1, 1, 1, 0.8 ],
"location": "",
"scaling": [ 0.64, 1 ],
"mode": "flat"
},
"assets": [
"textures/circle-in.png"
]
}

View File

@ -0,0 +1,26 @@
{
"name": "Menu: Circle Outer",
"type": "Gui",
"ignore": false,
"transform": {
"position": [ 0.86, 0.86, 0 ],
"rotation": {
"axis": [ 1, 0, 0 ],
"angle": 0
},
"scale": [ 1, 1, 1 ]
},
"metadata": {
"clickable": false,
"hoverable": true,
"uv": [ 0, 0, 1, 1 ],
"color": [ 1, 1, 1, 0.8 ],
"location": "",
"scaling": [ 0.64, 1 ],
"mode": "flat"
},
"assets": [
"textures/circle-out.png"
]
}

View File

@ -0,0 +1,26 @@
{
"name": "Menu: Main Text",
"type": "Gui",
"ignore": false,
"transform": {
"position": [ -0.922623, -0.854923, 0 ],
"rotation": {
"axis": [ 0, 0, 1 ],
"angle": 0
},
"scale": [ 1, 1, 1 ]
},
"metadata": {
"uv": [ 0, 0, 1, 1 ],
"location": "",
"scaling": "relative",
"debug": {
"moveable": false
},
"text settings": {
"scale": 2,
"font": "Coolvetica.ttf",
"string": "Grimgram"
}
}
}

View File

@ -0,0 +1,28 @@
{
"name": "Gui: Menu",
"type": "Gui",
"ignore": false,
"assets": [
"./textures/menu.png",
"./scripts/menu.lua"
],
"transform": {
"position": [ 0, 0, 0 ],
"rotation": {
"axis": [ 0, 0, 1 ],
"angle": 0
},
"scale": [ 1, 1, 1 ]
},
"metadata": {
"clickable": true,
"hoverable": true,
"uv": [ 0, 0, 1, 1 ],
"color": [ 1, 1, 1, 1 ],
"location": "",
"scaling": "relative",
"depth": 0,
"mode": "flat"
}
}

View File

@ -0,0 +1,36 @@
{
"name": "Menu: Close Option",
"type": "Gui",
"ignore": false,
"transform": {
"position": [ -0.75622, 0.638136, 0 ],
"rotation": {
"axis": [ 0, 0, 1 ],
"angle": 0
},
"scale": [ 1, 1, 1 ]
},
"metadata": {
"clickable": true,
"hoverable": true,
"uv": [ 0, 0, 1, 1 ],
"location": "",
"scaling": "relative",
"debug": {
"moveable": false
},
"events": {
"click": {
"name": "system:Quit",
"payload": {
"scene": "StartMenu"
}
}
},
"text settings": {
"legacy": false,
"string": "Quit"
}
}
}

View File

@ -0,0 +1,169 @@
Static = {
values = {},
get = function( obj )
if Static.values[""..obj:uid()] == nil then
Static.values[""..obj:uid()] = {}
end
return Static.values[""..obj:uid()]
end
}
local ent = ent
local scene = entities.currentScene()
local controller = entities.controller()
local camera = controller:getComponent("Camera")
local metadata = ent:getComponent("Metadata")
local masterdata = scene:getComponent("Metadata")
local children = {
mainText = ent:loadChild("./main-text.json",true),
circleOut = ent:loadChild("./circle-out.json",true),
circleIn = ent:loadChild("./circle-in.json",true),
start = ent:loadChild("./start.json",true),
quit = ent:loadChild("./quit.json",true),
}
local timer = Timer.new()
if not timer:running() then timer:start() end
local playSound = function( key )
local url = "/ui/" .. key .. ".ogg"
-- local assetLoader = scene:getComponent("Asset")
-- assetLoader:cache(ent:formatHookName("asset:Load.%UID%"), string.resolveURI(url))
end
local destination = function( obj, x, y, z )
local static = Static.get(obj)
local transform = obj:getComponent("Transform")
static.from = Vector3f(x or transform.position.x, y or transform.position.y, z or transform.position.z)
end
--[[
pcall( function()
local metadata = controller:getComponent("Metadata")
local json = json.readFromFile("./data/entities/player.json");
controller:callHook("object:UpdateMetadata.%UID%", {
overlay = json["metadata"]["overlay"]
})
camera:update(true);
end )
]]
destination(children.mainText, nil, -2, 0)
destination(children.circleOut, nil, -2, 0)
destination(children.circleIn, nil, 2, 0)
destination(children.start, -1.5, nil, 0)
destination(children.quit, -1.5, nil, 0)
ent:addHook("asset:Load.%UID%", function( json )
local filename = json["filename"]
if filename == "" or string.extension( filename ) ~= "ogg" then return false end
local sfx = ent:getComponent("Audio")
if not sfx:playing() then sfx:stop() end
sfx:load( filename )
sfx:setVolume( masterdata["volumes"]["sfx"] )
sfx:play()
return true
end )
if os.arch() == "Dreamcast" then
ent:bind( "tick", function(self)
-- circle in
if children.circleIn:uid() > 0 then
local transform = children.circleIn:getComponent("Transform")
transform.orientation = Quaternion.axisAngle( Vector3f(0, 0, 1), time.current() * -0.0125 )
end
-- circle out
if children.circleIn:uid() > 0 then
local transform = children.circleIn:getComponent("Transform")
transform.orientation = Quaternion.axisAngle( Vector3f(0, 0, 1), time.current() * 0.0125 )
end
if (window.keyPressed("Enter") or inputs.key("START")) and timer:elapsed() >= 1 then
timer:reset()
children.start:callHook("gui:Clicked.%UID%", {})
end
end )
else
ent:bind( "tick", function(self)
if (window.keyPressed("Enter") or inputs.key("START")) and timer:elapsed() >= 1 then
timer:reset()
children.start:callHook("gui:Clicked.%UID%", {})
end
local static = Static.get(self)
if not static.alpha then
static.alpha = 0
end
metadata["initialized"] = true;
if static.alpha >= 1.0 then
static.alpha = 1.0
else
static.alpha = static.alpha + time.delta() * 1.5
end
-- make background glow
local glow = 1 + math.sin(1.25 * time.current()) * 0.125
metadata["color"][1] = glow
metadata["color"][2] = glow
metadata["color"][3] = glow
metadata["alpha"] = static.alpha;
self:setComponent("Metadata", metadata)
camera:update(true);
-- iterate children in batch
for k, v in pairs(children) do
if v:uid() <= 0 then goto continue end
-- set alpha
local metadata = v:getComponent("Metadata")
metadata["alpha"] = static.alpha
v:setComponent("Metadata", metadata)
local transform = v:getComponent("Transform")
local static = Static.get(v)
-- translation
if not static.from then goto continue end
if not static.to then static.to = Vector3f(transform.position) end
if not static.delta then static.delta = 0 end
if static.delta >= 1 then
static.delta = 1
else
static.delta = static.delta + time.delta() * 1.5
transform.position = Vector3f.lerp( static.from, static.to, static.delta )
end
::continue::
end
-- circle in
child = children.circleIn
if child:uid() > 0 then
local static = Static.get( child )
local transform = child:getComponent("Transform")
local metadata = child:getComponent("Metadata")
-- rotation
local speed = metadata["hovered"] and 0.25 or 0.0125
static.time = (static.time or 0) + time.delta() * -speed
transform.orientation = Quaternion.axisAngle( Vector3f(0, 0, 1), static.time )
end
-- circle out
child = children.circleOut
if child:uid() > 0 then
local static = Static.get( child )
local transform = child:getComponent("Transform")
local metadata = child:getComponent("Metadata")
-- rotation
local speed = metadata["hovered"] and 0.25 or 0.0125
static.time = (static.time or 0) + time.delta() * speed
transform.orientation = Quaternion.axisAngle( Vector3f(0, 0, 1), static.time )
end
end )
end

View File

@ -0,0 +1,34 @@
{
"name": "Menu: Start Option",
"type": "Gui",
"ignore": false,
"transform": {
"position": [ -0.75622, 0.446468, 0 ],
"rotation": {
"axis": [ 0, 0, 1 ],
"angle": 0
},
"scale": [ 1, 1, 1 ]
},
"metadata": {
"clickable": true,
"hoverable": true,
"uv": [ 0, 0, 1, 1 ],
"location": "",
"scaling": "relative",
"debug": {
"moveable": false
},
"events": {
"click": {
"name": "game:Scene.Load",
"payload": { "scene": "SourceEngine" }
}
},
"text settings": {
"string": "Start",
"string1": "スタート"
}
}
}

View File

@ -0,0 +1,23 @@
{
"name": "Menu: Circle Inner",
"type": "Gui",
"ignore": false,
"transform": {
"position": [ -0.86, 0.86, 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": [ 0.64, 1 ],
"mode": "flat"
},
"assets": [
"./textures/circle-in.png"
]
}

View File

@ -0,0 +1,26 @@
{
"name": "Menu: Circle Outer",
"type": "Gui",
"ignore": false,
"transform": {
"position": [ -0.86, 0.86, 0 ],
"rotation": {
"axis": [ 1, 0, 0 ],
"angle": 0
},
"scale": [ 1, 1, 1 ]
},
"metadata": {
"clickable": false,
"hoverable": true,
"uv": [ 0, 0, 1, 1 ],
"color": [ 1, 1, 1, 0.8 ],
"location": "",
"scaling": [ 0.64, 1 ],
"mode": "flat"
},
"assets": [
"textures/circle-out.png"
]
}

View File

@ -0,0 +1,31 @@
{
"name": "Menu: Close Option",
"type": "Gui",
"ignore": false,
"transform": {
"position": [ -0.65544, -0.339642, 0 ],
"rotation": {
"axis": [ 0, 0, 1 ],
"angle": 0
},
"scale": [ 0.156407, 0.0788377, 1 ]
},
"metadata": {
"clickable": true,
"hoverable": true,
"uv": [ 0, 0, 1, 1 ],
"location": "",
"scaling": "relative",
"events": {
"click": {
"name": "menu:Close.%P-UID%",
"payload": {}
}
},
"text settings": {
"string": "Close",
"string1": "クローズ"
}
}
}

View File

@ -0,0 +1,25 @@
{
"name": "Menu: Command Text",
"type": "Gui",
"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 ],
"location": "",
"scaling": "relative",
"text settings": {
"stroke": [ 1, 0.749, 0.368, 1 ],
"color": [ 1, 0.749, 0.368, 1 ],
"string": "Menu",
"string1": "コマンド"
}
}
}

View File

@ -0,0 +1,25 @@
{
"name": "Gui: Icon",
"type": "Gui",
"ignore": false,
"transform": {
"position": [ 0, 0, 0 ],
"rotation": {
"axis": [ 0, 0, 1 ],
"angle": 0
},
"scale": [ 1, 1, 1 ]
},
"metadata": {
"gui": {
"position": [ -0.875, -0.775, 0 ],
"uv": [ 0, 0, 1, 1 ],
"color": [ 1, 1, 1, 1 ],
"location": "",
"scaling": "fixed"
}
},
"assets": [
"https://cdn..xyz//unity/Android/icon/icon_agyou01_skin1.png"
]
}

View File

@ -0,0 +1,23 @@
{
"name": "Menu: Main Scroller",
"type": "Gui",
"ignore": true,
"transform": {
"position": [ 0.98, -2, 0 ],
"rotation": {
"axis": [ 0, 0, 1 ],
"angle": 1.5707963
},
"scale": [ 0.16, 1, 1 ]
},
"hoverable": true,
"metadata": {
"uv": [ 0, 0, 1, 1 ],
"color": [ 0.113, 0.756, 0.988, 0.4 ],
"location": "",
"scaling": "relative"
},
"assets": [
"./textures/main.png"
]
}

View File

@ -0,0 +1,29 @@
{
"name": "Gui: Menu",
"type": "Gui",
"behaviors": [
"GuiBehavior"
],
"ignore": false,
"transform": {
"position": [ 0, 0, 0 ],
"rotation": {
"axis": [ 0, 0, 1 ],
"angle": 0
},
"scale": [ 1, 1, 1 ]
},
"metadata": {
"uv": [ 0, 0, 1, 1 ],
"color": [ 0.1, 0.05, 0.1, 0.5 ],
"location": "",
"scaling": "relative",
// "depth": 0.2,
"alpha": 1,
"mode": 1
},
"assets": [
// "./textures/menu.png",
"./scripts/menu.lua"
]
}

View File

@ -0,0 +1,45 @@
{
"name": "Menu: Close Option",
"type": "Gui",
"ignore": false,
"transform": {
"position": [ -0.65544, -0.157698, 0 ],
"rotation": {
"axis": [ 0, 0, 1 ],
"angle": 0
},
"scale": [ 0.156407, 0.0788377, 1 ]
},
"metadata": {
"clickable": true,
"hoverable": true,
"uv": [ 0, 0, 1, 1 ],
"location": "",
"scaling": "relative",
"debug": {
"moveable": true
},
"events": {
"click": [
{
"name": "menu:Close.%P-UID%",
"payload": {
"callback": {
"name": "game:Scene.Load",
"payload": {
"scene": "StartMenu"
},
"scope": "scene",
"delay": 0
}
}
}
]
},
"text settings": {
"string": "Quit",
"string1": "終了する"
}
}
}

View File

@ -0,0 +1,276 @@
local ent = ent
local scene = entities.currentScene()
local controller = entities.controller()
local metadata = ent:getComponent("Metadata")
local masterdata = scene:getComponent("Metadata")
local children = {
mainText = ent:loadChild("./main-text.json",true),
circleOut = ent:loadChild("./circle-out.json",true),
circleIn = ent:loadChild("./circle-in.json",true),
coverBar = ent:loadChild("./yellow-box.json",true),
commandText = ent:loadChild("./command-text.json",true),
tenkouseiOption = ent:loadChild("./tenkousei.json",true),
closeOption = ent:loadChild("./close.json",true),
quit = ent:loadChild("./quit.json",true),
}
local soundEmitter = ent:loadChild("./sound.json",true)
local timer = Timer.new()
if not timer:running() then timer:start() end
Static = {
values = {},
get = function( obj )
if obj == nil then
obj = scene
end
if Static.values[""..obj:uid()] == nil then
Static.values[""..obj:uid()] = {}
end
return Static.values[""..obj:uid()]
end
}
local destination = function( obj, x, y, z )
local static = Static.get(obj)
local transform = obj:getComponent("Transform")
static.from = Vector3f(x or transform.position.x, y or transform.position.y, z or transform.position.z)
end
-- circleOut
destination(children.circleOut, nil, -2, 0)
destination(children.circleIn, nil, 2, 0)
destination(children.coverBar, -1.5, nil, 0)
destination(children.commandText, -1.5, nil, 0)
destination(children.tenkouseiOption, -1.5, nil, 0)
destination(children.closeOption, -1.5, nil, 0)
destination(children.quit, -1.5, nil, 0)
local playSound = function( key )
local url = "/ui/" .. key .. ".ogg"
-- local assetLoader = scene:getComponent("Asset")
-- assetLoader:cache(soundEmitter:formatHookName("asset:Load.%UID%"), string.resolveURI(url), "")
end
ent:addHook("menu:Close.%UID%", function( json )
playSound("menu close")
if metadata["system"]["hooks"] == nil then metadata["system"]["hooks"] = {} end
metadata["system"]["hooks"]["onClose"] = json["callback"];
metadata["system"]["closing"] = true;
ent:setComponent("Metadata", metadata)
end )
playSound("menu open")
if os.arch() == "Dreamcast" then
ent:bind( "tick", function(self)
local static = Static.get(self)
if not static.alpha then
static.alpha = 0
end
if (window.keyPressed("Escape") or inputs.key("START")) and timer:elapsed() >= 1 then
timer:reset()
self:callHook("menu:Close.%UID%", {})
end
-- handle closing
if metadata["system"]["closing"] then
if static.alpha <= 0 then
static.alpha = 0
metadata["system"]["closing"] = false
metadata["system"]["closed"] = true
else
static.alpha = static.alpha - time.delta()
end
elseif metadata["system"]["closed"] then
timer:stop()
local callback = metadata["system"]["hooks"]["onClose"]
if callback then
local payload = callback["payload"]
local target = self
if callback["scope"] == "parent" then
target = ent:getParent()
elseif callback["scope"] == "scene" then
target = scene
end
if type(callback["delay"]) == "number" and target:uid() ~= self:uid() then
target:queueHook( callback["name"], payload, callback["delay"] );
else
target:callHook( callback["name"], payload );
end
end
controller:callHook("system:Control.%UID%", {
control = true
})
entities.destroy(self)
-- scene:queueHook("system:Destroy", { uid = self:uid() }, 0)
return
else
if not metadata["initialized"] then
static.alpha = 0
end
metadata["initialized"] = true;
if static.alpha >= 1.0 then
static.alpha = 1.0
else
static.alpha = static.alpha + time.delta() * 1.5
end
end
-- main text
local child = children.mainText
if child:uid() > 0 then
local transform = child:getComponent("Transform")
local speed = 0.5
transform.position.y = transform.position.y + time.delta() * speed
if transform.position.y > 2 then
transform.position.y = -2
end
end
-- circle in
if children.circleIn:uid() > 0 then
local static = Static.get( children.circleIn )
local transform = children.circleIn:getComponent("Transform")
-- rotation
local speed = 0.0125
static.time = (static.time or 0) + time.delta() * -speed
transform.orientation = Quaternion.axisAngle( Vector3f(0, 0, 1), static.time )
end
-- circle out
if children.circleOut:uid() > 0 then
local static = Static.get( children.circleOut )
local transform = children.circleOut:getComponent("Transform")
-- rotation
local speed = 0.0125
static.time = (static.time or 0) + time.delta() * speed
transform.orientation = Quaternion.axisAngle( Vector3f(0, 0, 1), static.time )
end
end )
else
ent:bind( "tick", function(self)
local static = Static.get(self)
if not static.alpha then
static.alpha = 0
end
if (window.keyPressed("Escape") or inputs.key("START")) and timer:elapsed() >= 1 then
timer:reset()
self:callHook("menu:Close.%UID%", {})
end
-- handle closing
if metadata["system"]["closing"] then
if static.alpha <= 0 then
static.alpha = 0
metadata["system"]["closing"] = false
metadata["system"]["closed"] = true
else
static.alpha = static.alpha - time.delta()
end
elseif metadata["system"]["closed"] then
timer:stop()
local callback = metadata["system"]["hooks"]["onClose"]
if callback then
local payload = callback["payload"]
local target = self
if callback["scope"] == "parent" then
target = ent:getParent()
elseif callback["scope"] == "scene" then
target = scene
end
if type(callback["delay"]) == "number" and target:uid() ~= self:uid() then
target:queueHook( callback["name"], payload, callback["delay"] );
else
target:callHook( callback["name"], payload );
end
end
entities.destroy(self)
-- scene:queueHook("system:Destroy", { uid = self:uid() }, 0)
return
else
if not metadata["initialized"] then
static.alpha = 0
end
metadata["initialized"] = true;
if static.alpha >= 1.0 then
static.alpha = 1.0
else
static.alpha = static.alpha + time.delta() * 1.5
end
end
metadata["alpha"] = static.alpha;
-- set alphas
for k, v in pairs(children) do
if v:uid() <= 0 then goto continue end
-- set alpha
local metadata = v:getComponent("Metadata")
metadata["alpha"] = static.alpha
local transform = v:getComponent("Transform")
local static = Static.get(v)
-- translation
if not static.from then goto continue end
if not static.to then static.to = Vector3f(transform.position) end
if not static.delta then static.delta = 0 end
if static.delta >= 1 then
static.delta = 1
else
static.delta = static.delta + time.delta() * 1.5
transform.position = Vector3f.lerp( static.from, static.to, static.delta )
v:setComponent("Metadata", metadata)
end
::continue::
end
-- main text
local child = children.mainText
if child:uid() > 0 then
local transform = child:getComponent("Transform")
local metadata = child:getComponent("Metadata")
local speed = metadata["gui"]["hovered"] and 0.75 or 0.5
transform.position.y = transform.position.y + time.delta() * speed
if transform.position.y > 2 then
transform.position.y = -2
end
end
-- circle in
if children.circleIn:uid() > 0 then
local static = Static.get( children.circleIn )
local transform = children.circleIn:getComponent("Transform")
local metadata = children.circleIn:getComponent("Metadata")
-- rotation
local speed = metadata["gui"]["hovered"] and 0.25 or 0.0125
static.time = (static.time or 0) + time.delta() * -speed
transform.orientation = Quaternion.axisAngle( Vector3f(0, 0, 1), static.time )
end
-- circle out
if children.circleOut:uid() > 0 then
local static = Static.get( children.circleOut )
local transform = children.circleOut:getComponent("Transform")
local metadata = children.circleOut:getComponent("Metadata")
-- rotation
local speed = metadata["gui"]["hovered"] and 0.25 or 0.0125
static.time = (static.time or 0) + time.delta() * speed
transform.orientation = Quaternion.axisAngle( Vector3f(0, 0, 1), static.time )
end
end )
end

View File

@ -0,0 +1,38 @@
{
"type": "Object",
"name": "Sound Emitter",
"ignore": false,
"assets": [
],
"behaviors": [
"SoundEmitterBehavior"
],
"transform": {
"position": [ 0, 0, 0 ],
"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": false,
"loop": false,
"volume": "sfx",
"rolloffFactor": 2
}
}
}

View File

@ -0,0 +1,25 @@
{
"name": "Menu: Tenkousei Option",
"type": "Gui",
"ignore": true,
"transform": {
"position": [ -0.65544, -0.52853, 0 ],
"rotation": {
"axis": [ 0, 0, 1 ],
"angle": 0
},
"scale": [ 0.156407, 0.0788377, 1 ]
},
"metadata": {
"clickable": true,
"hoverable": true,
"uv": [ 0, 0, 1, 1 ],
"location": "",
"scaling": "relative",
"text settings": {
"string": "",
"string1": "「転光生」"
}
}
}

View File

@ -0,0 +1,23 @@
{
"name": "Menu: Transient Portrait",
"type": "Gui",
"ignore": true,
"transform": {
"position": [ 0.76, 0.2, 0 ],
"rotation": {
"axis": [ 1, 0, 0 ],
"angle": 0
},
"scale": [ 0.43, 1, 1 ]
},
"metadata": {
"clickable": true,
"hoverable": false,
"uv": [ 0, 0, 1, 1 ],
"color": [ 1, 1, 1, 0 ],
"location": "",
"scaling": "relative",
"depth": 0.1
}
}

View File

@ -0,0 +1,21 @@
{
"name": "Menu: Transient Shadow",
"type": "Gui",
"ignore": true,
"transform": {
"position": [ 0.46, 0, 0 ],
"rotation": {
"axis": [ 1, 0, 0 ],
"angle": 0
},
"scale": [ 0.43, 1, 1 ]
},
"metadata": {
"uv": [ 0, 0, 1, 1 ],
"color": [ 1, 1, 1, 0 ],
"location": "",
"scaling": "relative",
"shader": 1,
"depth": 0.1
}
}

View File

@ -0,0 +1,25 @@
{
"name": "Menu: Left Rectangle",
"type": "Gui",
"ignore": false,
"transform": {
"position": [ -0.933374, 0, 0 ],
"rotation": {
"axis": [ 1, 0, 0 ],
"angle": 0
},
"scale": [ 0.067, 1, 1 ]
},
"metadata": {
"uv": [ 0, 0, 1, 1 ],
// "color": [ 1, 0.749, 0.368, 1 ],
"color": [ 1, 0.749, 0.368, 1 ],
"location": "",
"scaling": "relative",
"shader": 1,
"mode": "flat"
},
"assets": [
"./textures/square.png"
]
}

View File

@ -0,0 +1,22 @@
{
"name": "Gui: Text",
"type": "Object",
"behaviors": [
"GuiBehavior"
],
"ignore": false,
"transform": {
"position": [ 0, 0, 0 ],
"rotation": {
"axis": [ 0, 0, 1 ],
"angle": 0
},
"scale": [ 1, 1, 1 ]
},
"metadata": {
"uv": [ 0, 0, 1, 1 ],
"color": [ 1, 1, 1, 1 ],
"location": "",
"scaling": "relative"
}
}

View File

@ -0,0 +1,43 @@
{
"name": "Gui: Text",
"type": "Gui",
"ignore": true,
"transform": {
"position": [ 0, 0, 0 ],
"rotation": {
"axis": [ 0, 0, 1 ],
"angle": 0
},
"scale": [ 1, 1, 1 ]
},
"metadata": {
"text settings": {
"legacy": false,
"padding": [ 1, 1 ],
"spread": 4,
"weight": 0.48,
// "size": 36, "scale": 3,
// "size": 45, "scale": 2,
"size": 60, "scale": 1.5,
// "size": 72, "scale": 1.25,
// "size": 90, "scale": 1,
"sdf": false,
"font": "TAZUGANEGOTHICSTDN-BOLD.otf",
"kerning": 24,
// "font": "Coolvetica.ttf",
"stroke": [ 0, 0, 0, 0 ],
"color": [ 1, 1, 1, 1 ],
"direction": "down",
"align": "left",
"origin": [ 0, 0 ],
"string": "",
"world": false,
// "depth": 0,
"wrap": true
}
}
}

View File

@ -0,0 +1,29 @@
{
"name": "HUD Text",
"type": "Gui",
"ignore": false,
"transform": {
"position": [ -0.830591, -0.899509, 0 ],
"rotation": {
"axis": [ 1, 0, 0 ],
"angle": 0
},
"scale": [ 0.258737, 0.115371, 1 ]
},
"system": {
"hot reload": {
"enabled": true
}
},
"metadata": {
"uv": [ 0, 0, 1, 1 ],
"location": "",
"scaling": "relative",
"text settings": {
"stroke": [ 1, 0.749, 0.368, 1 ],
"color": [ 1, 0.749, 0.368, 1 ],
"depth": 0.5,
"string": "."
}
}
}

View File

@ -0,0 +1,37 @@
{
"type": "Object",
"name": "Light",
"behaviors": [ "LightBehavior" ],
"ignore": false,
"transform": {
"reference": true
},
"system": {
"renderer": {
// "limiter": 128
// "mode": "round robin"
// "mode": "once"
"mode": "in-range"
},
"hot reload": {
"enabled": true
}
},
"metadata": {
"light": {
"type": "point",
"color": [1, 1, 1],
"power": 100,
"fov": 90,
"bias": {
"constant": 1.25,
"slope": 1.75,
"shader": 0.000005 // 0.000005 //0.000000005
},
"radius": [0.5, 0],
"resolution": 512,
"shadows": true,
"dynamic": true
}
}
}

View File

@ -0,0 +1,79 @@
{
"name": "Graph",
"type": "Object",
"ignore": false,
// "behaviors": [ "LoadingBehavior" ],
"transform": {
"position": [ 0, 0, 0 ],
"rotation": { "axis": [ 0, 1, 0 ], "angle": 0 },
"scale": [ 1, 1, 1 ]
},
"metadata": {
"graph": {
"debug": {
"no cleanup": false,
"print": {
"tree": false,
"stats": false,
"lights": false,
"meshes": false,
"materials": false,
"textures": false
}
},
"sanitizer": {
"winding order": true
},
"exporter": {
"enabled": true,
"pretty": false,
"encoding": "auto",
"compression": "auto",
"quantize": false,
"precision": 4,
"combined": false,
"encode buffers": true,
"unwrap": "tagged",
"quit": true
},
"baking": {
"enabled": true,
"resolution": 2048,
"shadows": 1024,
"layers": 1,
"trigger": { "mode": "rendered", "quit": true },
// "trigger": { "mode": "key", "value": "B" },
"output": "./lightmap.%i.png",
"settings": {
"useInputMeshUvs": true,
"maxIterations": 4,
// "maxChartSize": 0,
"padding": 2,
// "texelsPerUnit": 0,
"bilinear": true,
"blockAlign": true,
"bruteForce": false,
"rotateChartsToAxis": false,
"rotateCharts": true
}
},
"renderer": {
"front face": "auto",
"cull mode": "back",
"filter": "linear",
"atlas": false,
"invert": true,
"skinned": false,
"render": true,
"separate": false
},
"lights": {
"lightmap": "auto",
// "disable if lightmapped": false,
"shadows": true
}
}
}
}

View File

@ -0,0 +1,111 @@
{
"name": "Player",
"type": "Object",
"behaviors": [
"PlayerBehavior",
"SoundEmitterBehavior"
],
"ignore": false,
/*
"transform": {
"position": [ 0, 0, 0 ],
"rotation": {
"axis": [ 0, 1, 0 ],
"angle": 0
},
"scale": [ 1, 1, 1 ]
},
*/
"assets": [
// { "filename": "./playerModel.json", "delay": 0 },
"./playerModel.json",
"./playerLight.json",
"./playerHands.json",
"./scripts/player.lua"
],
"system": {
"hot reload": {
"enabled": true
}
},
"metadata": {
"overlay": {
"transform": {
"position": [ 0, 0, -3 ],
"scale": [ 1.77778, -1, 1 ],
"orientation": [ 0, 0, 0, 1 ]
},
"floating": false,
"enabled": true,
"alpha": 1.0,
"cursor": {
"type": "mouse",
"radius": 0.05,
"color": [ 0.2, 0.2, 1.0, 1.0 ],
"enabled": false
}
},
"audio": {
"footstep": {
"volume": 0.5,
"list": [
"/footstep/1.ogg",
"/footstep/2.ogg"
]
}
},
"movement": {
"walk": 1,
"move": 4,
"run": 16,
"rotate": 1.5,
"air": 0.1,
"crouch": 1,
"jump": [ 0, 3, 0 ],
"look": 1,
"floored": {
"feet": [ 0, -1.5, 0 ],
// "floor": [ 0, -0.5, 0 ],
"floor": [ 0, -1.0, 0 ],
"print": false
}
},
"physics": {
"gravity": [ 0, -9.81, 0 ],
"inertia": [ 0, 0, 0 ],
"type": "capsule",
"radius": 1,
"height": 2,
"mass": 100,
"friction": 0.95,
"restitution": 0.0,
"shared": false
},
"camera": {
"offset": [ 0, 0, 0 ],
"position" : [ 0, 1.8, 0 ],
"scale": [ 1, 1, 1 ],
"invert": [ false, false, false ],
"limit": {
// "minima": [ null, -1.57079633, null ],
// "maxima": [ null, 1.57079633, null ],
"minima": [ null, -1.0, null ],
"maxima": [ null, 1.0, null ],
"current":[ null, 0, null ]
},
"settings": {
"fov" : 90.0,
"clip" : [ 0.1, 64.0 ],
"size" : [ 0, 0 ]
}
},
"use": {
"length": 5
}
}
}

View File

@ -0,0 +1,76 @@
{
"name": "Hands",
"type": "Object",
"ignore": true,
"transform": {
"position": [ 0, 0, 0 ],
"rotation": {
"axis": [ 0, 1, 0 ],
"angle": 0.0
},
"scale": [ 1, 1, 1 ]
},
"assets": [
],
"behaviors": [
"PlayerHandBehavior"
],
"metadata": {
"hands": {
"left": {
"controller": {
"model": "{indexcontroller}valve_controller_knu_1_0_left",
"color": [ 1, 1, 1, 1 ]
},
"light": {
"should": false,
"type": 3,
"color": [1, 1, 1],
"power": 50,
"fov": 80,
"shadows": true,
"bias": 0.000005,
"resolution": 512,
"static": false
},
"pointer": {
"color": [ 1, 0, 1, 1 ],
"length": 0, //128,
"width": 8,
"offset": [ 0, 0, 0 ],
"orientation": {
"axis": [ 1, 0, 0 ],
"angle": 0
}
}
},
"right": {
"controller": {
"model": "{indexcontroller}valve_controller_knu_1_0_right",
"color": [ 1, 1, 1, 1 ]
},
"light": {
"should": false,
"type": 3,
"color": [1, 1, 1],
"power": 50,
"fov": 80,
"shadows": true,
"bias": 0.000005,
"resolution": 512,
"static": false
},
"pointer": {
"color": [ 1, 0, 1, 1 ],
"length": 0, //128,
"width": 8,
"offset": [ 0, 0, 0 ],
"orientation": {
"axis": [ 1, 0, 0 ],
"angle": 0
}
}
}
}
}
}

View File

@ -0,0 +1,32 @@
{
"import": "/light.json",
"ignore": false,
"assets": [
],
"transform": {
// "track": "parent",
"position": [ 0, 1.7, 0 ]
},
"system": {
"hot reload": {
"enabled": true
}
},
"metadata": {
"light": {
"type": "spot",
"color": [1, 1, 1],
"power": 30,
"fov": 90,
"bias": {
"constant": 1.25,
"slope": 1.75,
"shader": 0.000005 //0.000000005
},
"radius": [0.001, 0],
"resolution": 512,
"shadows": false,
"dynamic": true
}
}
}

View File

@ -0,0 +1,62 @@
{
"type": "Object",
"name": "Player: Model",
"ignore": true,
"import": "/model.json",
"assets": [
"/player/bear.glb"
// { "filename": "/player/bear/graph.json" }
],
"behaviors": [
"PlayerModelBehavior"
],
"transform": {
"position": [ 0, -2.0, 0 ],
// "position": [ 12.5715, 3.53811, 7.6238 ],
// "position": [ 1.635, -0.384, -20.409 ], // -0.384
"rotation": {
"axis": [ 0, 1, 0 ],
"angle": 0
},
"scale": [ 0.16, 0.16, 0.16 ]
},
"system": {
"hot reload": {
"enabled": true
}
},
"metadata": {
"track": true,
"hide": true,
"graph": {
"debug": {
"print": {
"animations": true
}
},
"exporter": {
"enabled": false,
"unwrap": false,
"optimize": false
},
"baking": {
"enabled": false
},
"renderer": {
"cull mode": "back",
"filter": "linear"
},
"lights": {
"lightmap": false
},
"renderer": {
"flip textures": false,
"invert": false,
"skinned": true
},
"animations": {
"animation": "wank"
}
}
}
}

View File

@ -0,0 +1,17 @@
{
"assets": [],
"behaviors": [
"SoundEmitterBehavior"
],
"metadata": {
"holdable": true,
"physics": {
// "gravity": [ 0, -9.81, 0 ],
// "inertia": [10, 10, 10],
// "mass": 10,
"type": "bounding box",
"recenter": false
}
}
}

View File

@ -0,0 +1,10 @@
{
"name": "Scene",
"assets": [
"/gui.json"
],
"behaviors": [
"SceneBehavior",
"ExtSceneBehavior"
]
}

View File

@ -0,0 +1,117 @@
local ent = ent
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 soundEmitter = ent
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
-- 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 payload.user == ent:uid() then return end
-- if timer:elapsed() <= 0.125 then return end
-- timer:reset()
print("Processing use: " .. ent:name() .. " | " .. payload["depth"] )
if state == 0 or state == 3 then
state = 1
playSound("default_move")
if payload.uid ~= nil then
local user = entities.get( payload.user )
local userTransform = user:getComponent("Transform")
local delta = transform.position - userTransform.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 )

View File

@ -0,0 +1,241 @@
local ent = ent
local scene = entities.currentScene()
local metadata = ent:getComponent("Metadata")
local transform = ent:getComponent("Transform")
local physicsState = ent:getComponent("PhysicsState")
local camera = ent:getComponent("Camera")
local cameraTransform = camera:getTransform()
-- setup all timers
local timers = {
use = Timer.new(),
holp = Timer.new(),
flashlight = Timer.new(),
physcannon = Timer.new()
}
if not timers.use:running() then timers.use:start(); end
if not timers.holp:running() then timers.holp:start(); end
if not timers.flashlight:running() then timers.flashlight:start(); end
if not timers.physcannon:running() then timers.physcannon:start(); end
-- setup held object locals
local heldObject = {
uid = 0,
distance = 0,
smoothSpeed = 4,
scrollSpeed = 16,
momentum = Vector3f(0,0,0),
rotate = false,
}
-- setup light locals
local light = {
entity = nil
}
for k, v in pairs(ent:getChildren()) do
if v:name() == "Light" then
light.entity = v
end
end
if light.entity == nil then
light.entity = ent:loadChild("./playerLight.json",true)
end
light.metadata = light.entity:getComponent("Metadata")
light.transform = light.entity:getComponent("Transform")
light.power = light.metadata["light"]["power"]
light.origin = Vector3f(light.transform.position)
light.entity:setComponent("Metadata", { light = { power = 0 } })
-- sound emitter
local playSound = function( key, loop )
if not loop then loop = false end
local url = "/ui/" .. key .. ".ogg"
ent:callHook("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 = "/ui/" .. key .. ".ogg"
ent:callHook("sound:Stop.%UID%", {
filename = string.resolveURI(url, metadata["system"]["root"])
}, 0)
end
local useDistance = 6
local pullDistance = useDistance * 4
-- on tick
ent:bind( "tick", function(self)
-- eye transform
local flattenedTransform = cameraTransform:flatten()
flattenedTransform.forward = ( transform.forward + Vector3f( 0, cameraTransform.forward.y, 0 ) ):normalize();
-- toggle flashlight
if light.enabled then
local center = flattenedTransform.position
local direction = flattenedTransform.forward * 8
local offset = 0.25
local _, depth = physicsState:rayCast( center, direction )
if depth >= 0.5 then
depth = 0.5
elseif depth < 0 then
depth = 0.5
end
light.transform.position = center + direction * (depth - offset)
end
if timers.flashlight:elapsed() > 0.5 and inputs.key("F") then
timers.flashlight:reset()
local metadata = { light = { power = light.power } }
if light.entity:getComponent("Metadata")["light"]["power"] ~= light.power then
metadata["light"]["power"] = light.power
light.enabled = true
else
metadata["light"]["power"] = 0
light.enabled = false
end
light.entity:setComponent("Metadata", metadata)
playSound("flashlight")
end
-- fire use ray
if timers.use:elapsed() > 0.5 and (inputs.key("E") or inputs.key("R_Y")) then
timers.use:reset()
local center = flattenedTransform.position
local direction = flattenedTransform.forward * useDistance
local prop, depth = physicsState:rayCast( center, direction )
local payload = {
user = ent:uid(),
uid = prop and prop:uid() or 0,
depth = depth,
}
if prop then
prop:lazyCallHook("entity:Use.%UID%", payload)
end
ent:lazyCallHook("entity:Use.%UID%", payload)
end
-- update HOLP
if heldObject.uid == 0 then
local mouse2 = inputs.key("Mouse2") or inputs.key("R_TRIGGER");
if mouse2 then
--[[
local center = transform.position + cameraTransform.position
local direction = transform.forward + Vector3f( 0, cameraTransform.forward.y, 0 )
direction = direction:normalize() * 4
]]
local center = flattenedTransform.position
local direction = flattenedTransform.forward * pullDistance
local prop, depth = physicsState:rayCast( center, direction )
if depth >= 0 and prop and not string.matched( prop:name(), "/^worldspawn/" ) then
local heldObjectTransform = prop:getComponent("Transform")
local heldObjectPhysicsState = prop:getComponent("PhysicsState")
local strength = 500
local distanceSquared = (heldObjectTransform.position - flattenedTransform.position):magnitude()
heldObjectPhysicsState:applyImpulse( flattenedTransform.forward * -heldObjectPhysicsState:getMass() * strength / distanceSquared )
if timers.physcannon:elapsed() > 1.0 then
timers.physcannon:reset()
playSound("phys_tooHeavy")
end
end
end
else
local mouse1 = inputs.key("Mouse1") or inputs.key("L_TRIGGER");
local mouse3 = inputs.key("Mouse3");
local wheel = inputs.analog("MouseWheel")
if wheel ~= 0 then
heldObject.distance = heldObject.distance + (wheel / 120 * heldObject.scrollSpeed) * time.delta()
end
if mouse3 then
heldObject.rotate = not heldObject.rotate
end
local prop = entities.get( heldObject.uid )
local heldObjectTransform = prop:getComponent("Transform")
local heldObjectPhysicsState = prop:getComponent("PhysicsState")
if mouse1 and timers.physcannon:elapsed() > 0.5 then
timers.physcannon:reset()
heldObject.uid = 0
heldObjectPhysicsState:enableGravity(true)
heldObjectPhysicsState:applyImpulse( flattenedTransform.forward * heldObjectPhysicsState:getMass() * 1000 )
playSound("phys_launch"..math.random(1,4))
else
if heldObject.rotate then
heldObjectTransform.orientation = Quaternion.lookAt( (heldObjectTransform.position - flattenedTransform.position):normalize(), transform.up )
end
local forward = flattenedTransform.forward * heldObject.distance --flattenedTransform.orientation:rotate( Vector3f(0,0,1) )
if heldObject.smoothSpeed ~= 0 then
local target = flattenedTransform.position + forward
local offset = target - heldObjectTransform.position
local delta = offset * time.delta() * heldObject.smoothSpeed
local distance = delta:norm()
if distance > 0.001 then
if timers.holp:elapsed() > 0.125 then
timers.holp:reset()
heldObjectPhysicsState:setVelocity( delta * 20 )
end
else
heldObjectPhysicsState:setVelocity( Vector3f(0,0,0) )
end
else
heldObjectTransform.position = flattenedTransform.position + forward
end
end
end
end )
-- on use
ent:addHook( "entity:Use.%UID%", function( payload )
if payload.user ~= ent:uid() then return end
local validUse = false
if heldObject.uid == 0 and payload.depth > 0 then
local prop = entities.get( payload.uid )
local propMetadata = prop:getComponent("Metadata")
if propMetadata["holdable"] then
validUse = true
local offset = transform.position - prop:getComponent("Transform").position
heldObject.uid = payload.uid
heldObject.distance = offset:norm()
prop:getComponent("PhysicsState"):enableGravity(false)
else
validUse = not string.matched( prop:name(), "/^worldspawn/" )
end
elseif heldObject.uid ~= 0 then
validUse = true
local prop = entities.get( heldObject.uid )
local heldObjectPhysicsState = prop:getComponent("PhysicsState")
heldObjectPhysicsState:enableGravity(true)
heldObjectPhysicsState:applyImpulse( heldObject.momentum )
heldObject.uid = 0
heldObject.distance = 0
heldObject.momentum = Vector3f(0,0,0)
end
if validUse then
playSound("select")
else
playSound("deny")
end
end )

View File

@ -0,0 +1,20 @@
{
"type": "Object",
"name": "Sound Emitter",
"ignore": false,
"assets": [],
"behaviors": [ "SoundEmitterBehavior" ],
"transform": { "reference": true },
"system": {
"hot reload": { "enabled": true }
},
"metadata": {
"audio": {
"spatial": true,
"loop": false,
"volume": 1,
"rolloffFactor": 0.5,
"epsilon": 0.5
}
}
}

View File

@ -0,0 +1,31 @@
{
"name": "Gui: HTML",
"type": "Gui",
"ignore": true,
"assets": [],
"behaviors": [
"GuiHtmlBehavior"
],
"transform": {
"position": [ 0, 4, 0 ],
"rotation": {
"axis": [ 1, 0, 0 ],
"angle": 3.14159
},
"scale": [ 2, 2, 2 ]
},
"metadata": {
"clickable": true,
"hoverable": true,
"uv": [ 0, 0, 1, 1 ],
"color": [ 1, 1, 1, 1 ],
"location": "",
"scaling": "relative",
"depth": 0.2,
"world": true,
"size": [ 1600, 1600 ],
"html": "https://youtube.com/",
"ignore inputs": false
}
}

View File

@ -0,0 +1,34 @@
{
"name": "Gui: Loading",
"type": "Object",
"behaviors": [
// "GuiBehavior"
],
"assets": [
{ "filename": "./mcdonalds.json", "delay": 0 }
// { "filename": "./sh.json", "delay": 0 }
// { "filename": "./medsci.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": "コマンド"
}
}
}

View File

@ -0,0 +1,261 @@
{
"controller_type" : "generic",
"description" : "Default bindings",
"name" : "Generic Bindings",
"bindings": {
"/actions/global": {
"sources": [
{
"path": "/user/hand/right/input/a",
"mode": "button",
"inputs": {
"click": {
"output": "/actions/global/in/leftA"
}
}
},
{
"path": "/user/hand/left/input/a",
"mode": "button",
"inputs": {
"click": {
"output": "/actions/global/in/rightA"
}
}
},
{
"path": "/user/hand/left/input/b",
"mode": "button",
"inputs": {
"click": {
"output": "/actions/global/in/leftB"
}
}
},
{
"path": "/user/hand/right/input/b",
"mode": "button",
"inputs": {
"click": {
"output": "/actions/global/in/rightB"
}
}
},
{
"path": "/user/hand/left/input/trackpad",
"mode": "trackpad",
"inputs": {
"position": {
"output": "/actions/global/in/leftTrackpad"
},
"touch": {
"output": "/actions/global/in/leftTouchpad"
}
}
},
{
"path": "/user/hand/right/input/trackpad",
"mode": "trackpad",
"inputs": {
"position": {
"output": "/actions/global/in/rightTrackpad"
},
"touch": {
"output": "/actions/global/in/rightTouchpad"
}
}
},
{
"path": "/user/hand/left/input/trackpad",
"mode": "button",
"inputs": {
"click": {
"output": "/actions/global/in/leftClickpad"
}
}
},
{
"path": "/user/hand/right/input/trackpad",
"mode": "button",
"inputs": {
"click": {
"output": "/actions/global/in/right_Clickpad"
}
}
},
{
"path": "/user/hand/left/input/grip",
"mode": "force_sensor",
"inputs": {
"force": {
"output": "/actions/global/in/leftGrip"
}
}
},
{
"path": "/user/hand/right/input/grip",
"mode": "force_sensor",
"inputs": {
"force": {
"output": "/actions/global/in/rightGrip"
}
}
},
{
"path": "/user/hand/left/input/grip",
"mode": "grab",
"inputs": {
"grab": {
"output": "/actions/global/in/leftGrab"
}
}
},
{
"path": "/user/hand/right/input/grip",
"mode": "grab",
"inputs": {
"grab": {
"output": "/actions/global/in/rightGrab"
}
}
},
{
"path": "/user/hand/left/input/trigger",
"mode": "button",
"parameters": {
"haptic_amplitude": "0"
},
"inputs": {
"click": {
"output": "/actions/global/in/leftClick"
}
}
},
{
"path": "/user/hand/right/input/trigger",
"mode": "button",
"parameters": {
"haptic_amplitude": "0"
},
"inputs": {
"click": {
"output": "/actions/global/in/rightClick"
}
}
},
{
"path": "/user/hand/left/input/trigger",
"mode": "button",
"inputs": {
"click": {
"output": "/actions/global/in/leftTrigger"
}
}
},
{
"path": "/user/hand/right/input/trigger",
"mode": "button",
"inputs": {
"click": {
"output": "/actions/global/in/rightTrigger"
}
}
},
{
"path": "/user/hand/left/input/thumbstick",
"mode": "dpad_touch",
"parameters": {
"deadzone_pct": "85",
"overlap_pct": "0",
"sticky": "true"
},
"inputs": {
"north": {
"output": "/actions/global/in/leftDPadUp"
},
"south": {
"output": "/actions/global/in/leftDPadDown"
},
"east": {
"output": "/actions/global/in/leftDPadRight"
},
"west": {
"output": "/actions/global/in/leftDPadLeft"
}
}
},
{
"path": "/user/hand/right/input/thumbstick",
"mode": "dpad_touch",
"parameters": {
"deadzone_pct": "85",
"overlap_pct": "0",
"sticky": "true"
},
"inputs": {
"north": {
"output": "/actions/global/in/rightDPadUp"
},
"south": {
"output": "/actions/global/in/rightDPadDown"
},
"east": {
"output": "/actions/global/in/rightDPadRight"
},
"west": {
"output": "/actions/global/in/rightDPadLeft"
}
}
},
{
"path": "/user/hand/left/input/thumbstick",
"mode": "joystick",
"inputs": {
"position": {
"output": "/actions/global/in/leftThumbstick"
}
}
},
{
"path": "/user/hand/right/input/thumbstick",
"mode": "joystick",
"inputs": {
"position": {
"output": "/actions/global/in/rightThumbstick"
}
}
}
],
"poses": [
{
"output": "/actions/global/in/leftHandPose",
"path": "/user/hand/left/pose/raw"
},
{
"output": "/actions/global/in/rightHandPose",
"path": "/user/hand/right/pose/raw"
}
],
"haptics": [
{
"output": "/actions/global/out/leftHapticVibration",
"path": "/user/hand/left/output/haptic"
},
{
"output": "/actions/global/out/rightHapticVibration",
"path": "/user/hand/right/output/haptic"
}
],
"skeleton": [
{
"output": "/actions/global/in/leftHandSkeleton",
"path": "/user/hand/left/input/skeleton/left"
},
{
"output": "/actions/global/in/rightHandSkeleton",
"path": "/user/hand/right/input/skeleton/right"
}
]
}
}
}

View File

@ -0,0 +1,275 @@
{
"controller_type" : "knuckles",
"description" : "Default Index Knuckles bindings",
"name" : "Knuckles Bindings",
"bindings": {
"/actions/global": {
"sources": [
{
"path": "/user/hand/left/input/a",
"mode": "button",
"inputs": {
"click": {
"output": "/actions/global/in/a.left"
}
}
},
{
"path": "/user/hand/right/input/a",
"mode": "button",
"inputs": {
"click": {
"output": "/actions/global/in/a.right"
}
}
},
{
"path": "/user/hand/left/input/b",
"mode": "button",
"inputs": {
"click": {
"output": "/actions/global/in/b.left"
}
}
},
{
"path": "/user/hand/right/input/b",
"mode": "button",
"inputs": {
"click": {
"output": "/actions/global/in/b.right"
}
}
},
{
"path": "/user/hand/left/input/trackpad",
"mode": "trackpad",
"inputs": {
"position": {
"output": "/actions/global/in/trackpad.left"
},
"touch": {
"output": "/actions/global/in/touchpad.left"
}
}
},
{
"path": "/user/hand/right/input/trackpad",
"mode": "trackpad",
"inputs": {
"position": {
"output": "/actions/global/in/trackpad.right"
},
"touch": {
"output": "/actions/global/in/touchpad.right"
}
}
},
{
"path": "/user/hand/left/input/trackpad",
"mode": "button",
"inputs": {
"click": {
"output": "/actions/global/in/clickpad.left"
}
}
},
{
"path": "/user/hand/right/input/trackpad",
"mode": "button",
"inputs": {
"click": {
"output": "/actions/global/in/clickpad.right"
}
}
},
{
"path": "/user/hand/left/input/grip",
"mode": "force_sensor",
"inputs": {
"force": {
"output": "/actions/global/in/grip.left"
}
}
},
{
"path": "/user/hand/right/input/grip",
"mode": "force_sensor",
"inputs": {
"force": {
"output": "/actions/global/in/grip.right"
}
}
},
{
"path": "/user/hand/left/input/grip",
"mode": "grab",
"inputs": {
"grab": {
"output": "/actions/global/in/grab.left"
}
}
},
{
"path": "/user/hand/right/input/grip",
"mode": "grab",
"inputs": {
"grab": {
"output": "/actions/global/in/grab.right"
}
}
},
{
"path": "/user/hand/left/input/trigger",
"mode": "button",
"parameters": {
"haptic_amplitude": "0"
},
"inputs": {
"click": {
"output": "/actions/global/in/click.left"
}
}
},
{
"path": "/user/hand/right/input/trigger",
"mode": "button",
"parameters": {
"haptic_amplitude": "0"
},
"inputs": {
"click": {
"output": "/actions/global/in/click.right"
}
}
},
{
"path": "/user/hand/left/input/trigger",
"mode": "trigger",
"inputs": {
"click": {
"output": "/actions/global/in/trigger.left"
}
}
},
{
"path": "/user/hand/right/input/trigger",
"mode": "trigger",
"inputs": {
"click": {
"output": "/actions/global/in/trigger.right"
}
}
},
{
"path": "/user/hand/left/input/thumbstick",
"mode": "dpad_touch",
"parameters": {
"deadzone_pct": "85",
"overlap_pct": "0",
"sticky": "true"
},
"inputs": {
"north": {
"output": "/actions/global/in/dpadUp.left"
},
"south": {
"output": "/actions/global/in/dpadDown.left"
},
"east": {
"output": "/actions/global/in/dpadRight.left"
},
"west": {
"output": "/actions/global/in/dpadLeft.left"
}
}
},
{
"path": "/user/hand/right/input/thumbstick",
"mode": "dpad_touch",
"parameters": {
"deadzone_pct": "85",
"overlap_pct": "0",
"sticky": "true"
},
"inputs": {
"north": {
"output": "/actions/global/in/dpadUp.right"
},
"south": {
"output": "/actions/global/in/dpadDown.right"
},
"east": {
"output": "/actions/global/in/dpadRight.right"
},
"west": {
"output": "/actions/global/in/dpadLeft.right"
}
}
},
{
"path": "/user/hand/left/input/thumbstick",
"mode": "joystick",
"inputs": {
"position": {
"output": "/actions/global/in/thumbstick.left"
},
"click": {
"output": "/actions/global/in/thumbclick.left"
}
}
},
{
"path": "/user/hand/right/input/thumbstick",
"mode": "joystick",
"inputs": {
"position": {
"output": "/actions/global/in/thumbstick.right"
},
"click": {
"output": "/actions/global/in/thumbclick.right"
}
}
}
],
"poses": [
{
"output": "/actions/global/in/handPose.left",
"path": "/user/hand/left/pose/raw"
},
{
"output": "/actions/global/in/handPose.right",
"path": "/user/hand/right/pose/raw"
},
{
"output": "/actions/global/in/handTip.left",
"path": "/user/hand/left/pose/tip"
},
{
"output": "/actions/global/in/handTip.right",
"path": "/user/hand/right/pose/tip"
}
],
"haptics": [
{
"output": "/actions/global/out/hapticVibration.left",
"path": "/user/hand/left/output/haptic"
},
{
"output": "/actions/global/out/hapticVibration.right",
"path": "/user/hand/right/output/haptic"
}
],
"skeleton": [
{
"output": "/actions/global/in/handSkeleton.left",
"path": "/user/hand/left/input/skeleton/left"
},
{
"output": "/actions/global/in/handSkeleton.right",
"path": "/user/hand/right/input/skeleton/right"
}
]
}
}
}

View File

@ -0,0 +1,165 @@
{
"default_bindings": [
{
"controller_type": "knuckles",
"binding_url": "./openvr_bindings_knuckles.json"
}
],
"actions": [
{
"name": "/actions/global/in/a.left",
"type": "boolean"
},
{
"name": "/actions/global/in/a.right",
"type": "boolean"
},
{
"name": "/actions/global/in/b.left",
"type": "boolean"
},
{
"name": "/actions/global/in/b.right",
"type": "boolean"
},
{
"name": "/actions/global/in/trackpad.left",
"type": "vector2"
},
{
"name": "/actions/global/in/touchpad.left",
"type": "vector2"
},
{
"name": "/actions/global/in/trackpad.right",
"type": "vector2"
},
{
"name": "/actions/global/in/touchpad.right",
"type": "vector2"
},
{
"name": "/actions/global/in/clickpad.left",
"type": "boolean"
},
{
"name": "/actions/global/in/clickpad.right",
"type": "boolean"
},
{
"name": "/actions/global/in/grip.left",
"type": "vector1"
},
{
"name": "/actions/global/in/grip.right",
"type": "vector1"
},
{
"name": "/actions/global/in/grab.left",
"type": "boolean"
},
{
"name": "/actions/global/in/grab.right",
"type": "boolean"
},
{
"name": "/actions/global/in/click.left",
"type": "boolean"
},
{
"name": "/actions/global/in/click.right",
"type": "boolean"
},
{
"name": "/actions/global/in/trigger.left",
"type": "vector1"
},
{
"name": "/actions/global/in/trigger.right",
"type": "vector1"
},
{
"name": "/actions/global/in/dpadUp.left",
"type": "boolean"
},
{
"name": "/actions/global/in/dpadDown.left",
"type": "boolean"
},
{
"name": "/actions/global/in/dpadRight.left",
"type": "boolean"
},
{
"name": "/actions/global/in/dpadLeft.left",
"type": "boolean"
},
{
"name": "/actions/global/in/dpadUp.right",
"type": "boolean"
},
{
"name": "/actions/global/in/dpadDown.right",
"type": "boolean"
},
{
"name": "/actions/global/in/dpadRight.right",
"type": "boolean"
},
{
"name": "/actions/global/in/dpadLeft.right",
"type": "boolean"
},
{
"name": "/actions/global/in/thumbclick.left",
"type": "boolean"
},
{
"name": "/actions/global/in/thumbclick.right",
"type": "boolean"
},
{
"name": "/actions/global/in/thumbstick.left",
"type": "vector2"
},
{
"name": "/actions/global/in/thumbstick.right",
"type": "vector2"
},
{
"name": "/actions/global/in/handPose.left",
"type": "pose"
},
{
"name": "/actions/global/in/handPose.right",
"type": "pose"
},
{
"name": "/actions/global/in/handTip.left",
"type": "pose"
},
{
"name": "/actions/global/in/handTip.right",
"type": "pose"
},
{
"name": "/actions/global/out/hapticVibration.left",
"type": "vibration"
},
{
"name": "/actions/global/out/hapticVibration.right",
"type": "vibration"
}
],
"action_sets": [
{
"name": "/actions/global",
"usage": "leftright"
}
],
"localization" : [
{
"language_tag": "en_us"
}
]
}

View File

@ -0,0 +1,60 @@
{
"name": "Scene",
"assets": [
"/gui.json"
],
"behaviors": [
"SceneBehavior",
"ExtSceneBehavior"
],
"system": {
"hot reload": {
"enabled": true
},
"renderer": {
"clear values": [
[ 0, 0, 0, 0 ]
],
"shader": {
"mode": 0,
"scalar": 16,
"parameters": [ 0, 0, 0, "time" ]
}
}
},
"metadata": {
// sky, and not skybox, so i can supply parameters for global lighting
"sky": {
// sky.box.filename, so i can add in additional parameters, for example, using it as a render target
"box": {
"filename": "/skybox/%d.png"
}
},
"menus": {
"pause": "/gui/pause/menu.json"
},
"light": {
"enabled": true,
"ambient": [ 0.0, 0.0, 0.0 ],
// "ambient": [ 0.1, 0.1, 0.2 ],
"exposure": 0.125,
"gamma": 2.2,
"bloom": {
"threshold": 1.0,
"scale": 1.0,
"strength": 0.25,
"sigma": 1.0,
"samples": 4
},
"shadows": {
"enabled": true
}
},
"noise": {
"size": [ 32, 32, 32 ]
}
}
}

View File

@ -0,0 +1,32 @@
{
"name": "Gui: Loading",
"type": "Object",
"behaviors": [
// "GuiBehavior"
],
"assets": [
{ "filename": "./sm64.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": "コマンド"
}
}
}

View File

@ -0,0 +1,19 @@
{
"import": "/player.json",
"assets": [
// { "filename": "/gui/hud/hud.json", "delay": 0 }
],
"metadata": {
"movement": {
"jump": [0, 1, 0],
"floored": {
"feet": [ 0, 0, 0 ],
"floor": [ 0, -0.8, 0 ]
}
},
"physics": {
"radius": 0.25,
"height": 0.25
}
}
}

View File

@ -0,0 +1,21 @@
{
"import": "/scene.json",
"assets": [
// "./loading.json",
"./sm64.json"
],
"metadata": {
"light": {
// "ambient": [ 0, 0, 0 ],
// "ambient": [ 0.025, 0.025, 0.025 ],
// "ambient": [ 0.075, 0.075, 0.075 ],
"ambient": [ 0.1, 0.1, 0.1 ],
// "ambient": [ 0.4, 0.4, 0.4 ],
// "ambient": [ 0.8, 0.8, 0.8 ],
"fog-": {
}
}
}
}

View File

@ -0,0 +1,30 @@
{
"import": "/model.json",
"assets": [
{ "filename": "./models/sm64_bbb.glb" }
// { "filename": "./models/sm64_bbb/graph.json" }
],
"metadata": {
"graph": {
"baking": { "enabled": true },
"renderer": {
"cull mode": "none",
"filter": "nearest"
},
"tags": {
"/^worldspawn/": {
"physics": { "type": "mesh", "static": true },
"grid": { "size": [3,1,3], "epsilon": 1.0, "cleanup": true, "print": true },
"optimize mesh": { "simplify": 0 },
"unwrap mesh": true
},
"info_player_spawn": { "action": "attach", "filename": "./player.json" },
"Material.071_574B138E_c.bmp": { "material": { "modeAlpha": "blend" } },
"Material.070_41A41EE3_c.bmp": { "material": { "modeAlpha": "blend" } },
"light_sun": { "light": { "power": 25000000 } }
}
}
}
}

View File

@ -0,0 +1,48 @@
{
"import": "/model.json",
"metadata": {
"graph": {
// "renderer": { "separate": true },
"baking": { "enabled": true },
"tags": {
// exact matches
"worldspawn": {
"physics": { "type": "mesh", "static": true },
"grid": { "size": [3,1,3], "epsilon": 1.0, "cleanup": true, "print": true },
"unwrap mesh": true,
"optimize mesh": { "simplify": 0 }
},
"worldspawn_skybox": {
"grid": { "size": [3,1,3], "epsilon": 1.0, "cleanup": true, "print": true },
"unwrap mesh": true,
"optimize mesh": { "simplify": 0 }
},
"info_player_spawn": { "action": "attach", "filename": "./player.json", "transform": { "orientation": [ 0, 1, 0, 0 ] } },
"light_environment": { "ignore": true, "transform": { "orientation": [0,0,0,1] }, "light": {
// "color": [0.1, 0.1, 0.1],
"power": 10000,
"global": true,
"bias": {
"constant": 1.25,
"slope": 1.75,
"shader": 0.000000000005
},
"radius": [8, 0],
"resolution": 1024
} },
// "/^light_[^e]/": { "ignore": true },
// regexp matches
"/^worldspawn_/": { "physics": { "type": "mesh", "static": true } },
"/^func_door_/": { "action": "load", "payload": { "import": "/door.json", "metadata": { "angle":-1.570795, "normal": [-1,0,0] } } },
"/^prop_door_/": { "action": "load", "payload": { "import": "/door.json", "metadata": { "angle":-1.570795, "normal": [-1,0,0] } } },
"/^prop_static/": { /*"action": "load", "payload": { "import": "/prop.json", "metadata": { "physics": { "gravity": [ 0, 0, 0 ] } } }*/ },
"/^prop_dynamic/": { /*"action": "load", "payload": { "import": "/prop.json", "metadata": { "physics": { "gravity": [ 0, 0, 0 ] } } }*/ },
"/^func_physbox/": { "action": "load", "payload": { "import": "/prop.json" } },
"/^prop_physics/": { "action": "load", "payload": { "import": "/prop.json" } },
"/^tools\\/toolsnodraw/": { "material": { "base": [ 1.0, 1.0, 1.0, 0.0 ] } }
}
}
}
}

View File

@ -0,0 +1,27 @@
{
"import": "./base_sourceengine.json",
"assets": [
// { "filename": "./models/gm_construct.glb" }
{ "filename": "./models/gm_construct/graph.json" }
],
"metadata": {
"graph": {
"assets": [
"./audio/soundscape/ambience.ogg"
],
"tags": {
// exact matches
// "worldspawn_skybox": { "ignore": true },
"worldspawn_water": {},
// regex matches
"/^gm_construct\\/water/": { "material": {
"base": [ 0.027, 0.227, 0.259, 0.5 ],
"fRoughness": 0.3,
"fAlphaCutoff": 0.5,
"modeAlpha": "blend"
} }
}
}
}
}

View File

@ -0,0 +1,32 @@
{
"name": "Gui: Loading",
"type": "Object",
"behaviors": [
"GuiBehavior"
],
"assets": [
{ "filename": "./sourceengine.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": "コマンド"
}
}
}

View File

@ -0,0 +1,37 @@
{
"import": "./base_sourceengine.json",
"assets": [
// { "filename": "./models/mds_mcdonalds.glb" }
{ "filename": "./models/mds_mcdonalds/graph.json" },
{ "filename": "/burger.json", "delay": 1 }
],
"metadata": {
"graph": {
"assets": [
"./audio/soundscape/sh2_ambience.ogg"
],
"tags": {
// exact matches
"func_door_rotating_5473": { "action": "load", "payload": { "import": "/door.json", "metadata": { "angle":-1.570795, "normal": [1,0,0] } } },
"func_door_rotating_5509": { "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_5584": { "action": "load", "payload": { "import": "/door.json", "metadata": { "angle":-1.570795, "normal": [1,0,0] } } },
// regex matches
// "/^prop_physics_override/": { "action": "load", "payload": { "import": "/prop.json", "metadata": { "physics": { "gravity": [ 0, 0, 0 ] } } } },
// "/^prop_physics_[^o]/": { "action": "load", "payload": { "import": "/prop.json" } },
"/^tools\\/toolsnodraw/": { "material": {
"base": [ 1.0, 1.0, 1.0, 1.0 ],
"emissive": [ 0.0, 0.0, 0.0, 0.0 ],
"fMetallic": 0.0,
"fRoughness": 0.10000000149011612,
"fOcclusion": 1.0,
"fAlphaCutoff": 0.5,
"iAlbedo": 27,
"modeAlpha": 1
} }
}
}
}
}

View File

@ -0,0 +1,10 @@
{
"import": "/player.json",
"assets": [
// { "filename": "/gui/hud/hud.json", "delay": 0 }
],
"transform": {
"orientation": [ 0, 1, 0, 0 ]
}
// "metadata": { "physics": { "gravity": [ 0, 0, 0 ] } }
}

View File

@ -0,0 +1,24 @@
{
"import": "./base_sourceengine.json",
"assets": [
// { "filename": "./models/rp_downtown_v2.glb" }
{ "filename": "./models/rp_downtown_v2/graph.json" }
],
"metadata": {
"graph": {
"assets": [
"./audio/soundscape/ambience.ogg"
],
"renderer": { "separate": true },
"tags": {
// exact matches
"worldspawn_skybox": { "ignore": true },
// regex matches
"/^light_/": { "ignore": true },
"/^func/": { "ignore": true },
"/^prop/": { "ignore": true }
}
}
}
}

View File

@ -0,0 +1,44 @@
{
"import": "/scene.json",
"assets": [
"./sourceengine.json"
// { "filename": "./loading.json", "delay": 0.5 }
],
"metadata": {
"light": {
"ambient": [ 0, 0, 0 ],
// "ambient": [ 0.05, 0.05, 0.05 ],
// "ambient": [ 0.15, 0.15, 0.15 ],
// "ambient": [ 0.5, 0.5, 0.5 ],
// "ambient": [ 0.8, 0.8, 0.8 ],
// "ambient": [ 0.1, 0.1, 0.2 ],
"exposure": 0.125,
"gamma": 2.2, // 2.2,
"bloom": {
"threshold": 1.2,
"scale": 1.0,
"strength": 1,
"sigma": 2.0,
"samples": 4
},
"fog-": {
// "color": [ 0.1, 0.1, 0.1 ],
// "color": [ 0.2, 0.2, 0.2 ],
"color": [ 0.3, 0.3, 0.3 ],
"range": [ 64, 256 ],
"step scale": 4,
"absorbtion": 0.0125,
"density": {
"threshold": 0.35,
"multiplier": 2.0,
"scale": 25.0,
"offset": [0.2, 0, 1],
"timescale": 32
}
}
}
}
}

View File

@ -0,0 +1,56 @@
{
"import": "./base_sourceengine.json",
"assets": [
// { "filename": "./models/sh2_mcdonalds.glb" }
{ "filename": "./models/sh2_mcdonalds/graph.json" }
],
"metadata": {
"graph": {
"lights": {
"scale": 2
},
"assets": [
"./audio/soundscape/sh2_ambience.ogg"
],
"tags": {
// exact matches
/*
"worldspawn_sh2": {
"physics": { "type": "mesh", "static": true },
"grid": { "size": [9,1,9], "epsilon": 1.0, "cleanup": true, "print": true },
"unwrap mesh": true,
"optimize mesh": { "simplify": 0 }
},
*/
"/^worldspawn_barrier$/": { "ignore": true },
// "/^worldspawn_skybox/": { "ignore": true },
"func_door_rotating_5473": { "action": "load", "payload": { "import": "/door.json", "metadata": { "angle":-1.570795, "normal": [1,0,0] } } },
"func_door_rotating_5509": { "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_5584": { "action": "load", "payload": { "import": "/door.json", "metadata": { "angle":-1.570795, "normal": [1,0,0] } } },
"func_door_rotating_9120": { "action": "load", "payload": { "import": "/door.json", "metadata": { "angle":-1.570795, "normal": [0,0,1] } } },
// regex matches
// "/^prop_physics_[^o]/": { "action": "load", "payload": { "import": "/prop.json" } },
// "/^prop_physics_override/": { "action": "load", "payload": {} },
// "/^prop_physics_/": { "action": "load", "payload": {} },
// "/^func_physbox/": { "action": "load", "payload": {} },
"/^.+?_phys.+?[^o]/": { "action": "load", "payload": { "import": "/prop.json" } },
"materials/models/props_wasteland/prison_lamp001a": { "material": { "emissive": [0, 0, 0, 0] } },
"/^tools\\/toolsnodraw/": { "material": {
"base": [ 1.0, 1.0, 1.0, 1.0 ],
"emissive": [ 0.0, 0.0, 0.0, 0.0 ],
"fMetallic": 0.0,
"fRoughness": 0.10000000149011612,
"fOcclusion": 1.0,
"fAlphaCutoff": 0.5,
"iAlbedo": 27,
"modeAlpha": 1
} },
"/alpha_mtl/": { "material": { "modeAlpha": "blend" } }
}
}
}
}

View File

@ -0,0 +1,7 @@
{
// "import": "./rp_downtown_v2.json"
"import": "./ss2_medsci1.json"
// "import": "./sh2_mcdonalds.json"
// "import": "./mds_mcdonalds.json"
// "import": "./gm_construct.json"
}

View File

@ -0,0 +1,18 @@
{
"import": "./base_sourceengine.json",
"assets": [
// { "filename": "./models/ss2_medsci1_small.glb" }
{ "filename": "./models/ss2_medsci1_small/graph.json" }
],
"metadata": {
"graph": {
"assets": [
"./audio/music/medsci1.ogg"
],
"tags": {
"/^prop_/": { "action": "load", "payload": { "import": "/prop.json", "metadata": { "physics": { "gravity": [ 0, 0, 0 ] } } } },
"/^func_/": { "action": "load", "payload": { "import": "/prop.json", "metadata": { "physics": { "gravity": [ 0, 0, 0 ] } } } }
}
}
}
}

View File

@ -0,0 +1,16 @@
{
"import": "/player.json",
"assets": [
{ "filename": "/hands.json", "delay": 0 }
],
"system": {
"physics": {
"gravity": [ 0, 0, 0 ],
"clamp": {
"x": [0, 0],
"y": [0, 0],
"z": [0, 0]
}
}
}
}

View File

@ -0,0 +1,19 @@
{
"type": "Main Menu",
"behaviors": [
"SceneBehavior",
"ExtSceneBehavior"
],
"assets": [
"/gui.json",
"/ui/main menu.ogg",
"/gui/mainmenu/menu.json"
],
"metadata": {
"volumes": {
"sfx": 0.25,
"bgm": 0.15,
"voice": 1.0
}
}
}

389
bin/data/scripts/json.lua Normal file
View File

@ -0,0 +1,389 @@
--
-- json.lua
--
-- Copyright (c) 2020 rxi
--
-- Permission is hereby granted, free of charge, to any person obtaining a copy of
-- this software and associated documentation files (the "Software"), to deal in
-- the Software without restriction, including without limitation the rights to
-- use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
-- of the Software, and to permit persons to whom the Software is furnished to do
-- so, subject to the following conditions:
--
-- The above copyright notice and this permission notice shall be included in all
-- copies or substantial portions of the Software.
--
-- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-- SOFTWARE.
--
local json = { _version = "0.1.2" }
-------------------------------------------------------------------------------
-- Encode
-------------------------------------------------------------------------------
local encode
local escape_char_map = {
[ "\\" ] = "\\",
[ "\"" ] = "\"",
[ "\b" ] = "b",
[ "\f" ] = "f",
[ "\n" ] = "n",
[ "\r" ] = "r",
[ "\t" ] = "t",
}
local escape_char_map_inv = { [ "/" ] = "/" }
for k, v in pairs(escape_char_map) do
escape_char_map_inv[v] = k
end
local function escape_char(c)
return "\\" .. (escape_char_map[c] or string.format("u%04x", c:byte()))
end
local function encode_nil(val)
return "null"
end
local function encode_table(val, stack)
local res = {}
stack = stack or {}
-- Circular reference?
if stack[val] then error("circular reference") end
stack[val] = true
if rawget(val, 1) ~= nil or next(val) == nil then
-- Treat as array -- check keys are valid and it is not sparse
local n = 0
for k in pairs(val) do
if type(k) ~= "number" then
error("invalid table: mixed or invalid key types")
end
n = n + 1
end
if n ~= #val then
error("invalid table: sparse array")
end
-- Encode
for i, v in ipairs(val) do
table.insert(res, encode(v, stack))
end
stack[val] = nil
return #res == 0 and "{}" or "[" .. table.concat(res, ",") .. "]"
-- return "[" .. table.concat(res, ",") .. "]"
else
-- Treat as an object
for k, v in pairs(val) do
if type(k) ~= "string" then
error("invalid table: mixed or invalid key types")
end
table.insert(res, encode(k, stack) .. ":" .. encode(v, stack))
end
stack[val] = nil
return "{" .. table.concat(res, ",") .. "}"
end
end
local function encode_string(val)
return '"' .. val:gsub('[%z\1-\31\\"]', escape_char) .. '"'
end
local function encode_number(val)
-- Check for NaN, -inf and inf
if val ~= val or val <= -math.huge or val >= math.huge then
error("unexpected number value '" .. tostring(val) .. "'")
end
return string.format("%.14g", val)
end
local type_func_map = {
[ "nil" ] = encode_nil,
[ "table" ] = encode_table,
[ "string" ] = encode_string,
[ "number" ] = encode_number,
[ "boolean" ] = tostring,
}
encode = function(val, stack)
local t = type(val)
local f = type_func_map[t]
if f then
return f(val, stack)
end
error("unexpected type '" .. t .. "'")
end
function json.encode(val)
return ( encode(val) )
end
-------------------------------------------------------------------------------
-- Decode
-------------------------------------------------------------------------------
local parse
local function create_set(...)
local res = {}
for i = 1, select("#", ...) do
res[ select(i, ...) ] = true
end
return res
end
local space_chars = create_set(" ", "\t", "\r", "\n")
local delim_chars = create_set(" ", "\t", "\r", "\n", "]", "}", ",")
local escape_chars = create_set("\\", "/", '"', "b", "f", "n", "r", "t", "u")
local literals = create_set("true", "false", "null")
local literal_map = {
[ "true" ] = true,
[ "false" ] = false,
[ "null" ] = nil,
}
local function next_char(str, idx, set, negate)
for i = idx, #str do
if set[str:sub(i, i)] ~= negate then
return i
end
end
return #str + 1
end
local function decode_error(str, idx, msg)
local line_count = 1
local col_count = 1
for i = 1, idx - 1 do
col_count = col_count + 1
if str:sub(i, i) == "\n" then
line_count = line_count + 1
col_count = 1
end
end
error( string.format("%s at line %d col %d", msg, line_count, col_count) )
end
local function codepoint_to_utf8(n)
-- http://scripts.sil.org/cms/scripts/page.php?site_id=nrsi&id=iws-appendixa
local f = math.floor
if n <= 0x7f then
return string.char(n)
elseif n <= 0x7ff then
return string.char(f(n / 64) + 192, n % 64 + 128)
elseif n <= 0xffff then
return string.char(f(n / 4096) + 224, f(n % 4096 / 64) + 128, n % 64 + 128)
elseif n <= 0x10ffff then
return string.char(f(n / 262144) + 240, f(n % 262144 / 4096) + 128,
f(n % 4096 / 64) + 128, n % 64 + 128)
end
error( string.format("invalid unicode codepoint '%x'", n) )
end
local function parse_unicode_escape(s)
local n1 = tonumber( s:sub(1, 4), 16 )
local n2 = tonumber( s:sub(7, 10), 16 )
-- Surrogate pair?
if n2 then
return codepoint_to_utf8((n1 - 0xd800) * 0x400 + (n2 - 0xdc00) + 0x10000)
else
return codepoint_to_utf8(n1)
end
end
local function parse_string(str, i)
local res = ""
local j = i + 1
local k = j
while j <= #str do
local x = str:byte(j)
if x < 32 then
decode_error(str, j, "control character in string")
elseif x == 92 then -- `\`: Escape
res = res .. str:sub(k, j - 1)
j = j + 1
local c = str:sub(j, j)
if c == "u" then
local hex = str:match("^[dD][89aAbB]%x%x\\u%x%x%x%x", j + 1)
or str:match("^%x%x%x%x", j + 1)
or decode_error(str, j - 1, "invalid unicode escape in string")
res = res .. parse_unicode_escape(hex)
j = j + #hex
else
if not escape_chars[c] then
decode_error(str, j - 1, "invalid escape char '" .. c .. "' in string")
end
res = res .. escape_char_map_inv[c]
end
k = j + 1
elseif x == 34 then -- `"`: End of string
res = res .. str:sub(k, j - 1)
return res, j + 1
end
j = j + 1
end
decode_error(str, i, "expected closing quote for string")
end
local function parse_number(str, i)
local x = next_char(str, i, delim_chars)
local s = str:sub(i, x - 1)
local n = tonumber(s)
if not n then
decode_error(str, i, "invalid number '" .. s .. "'")
end
return n, x
end
local function parse_literal(str, i)
local x = next_char(str, i, delim_chars)
local word = str:sub(i, x - 1)
if not literals[word] then
decode_error(str, i, "invalid literal '" .. word .. "'")
end
return literal_map[word], x
end
local function parse_array(str, i)
local res = {}
local n = 1
i = i + 1
while 1 do
local x
i = next_char(str, i, space_chars, true)
-- Empty / end of array?
if str:sub(i, i) == "]" then
i = i + 1
break
end
-- Read token
x, i = parse(str, i)
res[n] = x
n = n + 1
-- Next token
i = next_char(str, i, space_chars, true)
local chr = str:sub(i, i)
i = i + 1
if chr == "]" then break end
if chr ~= "," then decode_error(str, i, "expected ']' or ','") end
end
return res, i
end
local function parse_object(str, i)
local res = {}
i = i + 1
while 1 do
local key, val
i = next_char(str, i, space_chars, true)
-- Empty / end of object?
if str:sub(i, i) == "}" then
i = i + 1
break
end
-- Read key
if str:sub(i, i) ~= '"' then
decode_error(str, i, "expected string for key")
end
key, i = parse(str, i)
-- Read ':' delimiter
i = next_char(str, i, space_chars, true)
if str:sub(i, i) ~= ":" then
decode_error(str, i, "expected ':' after key")
end
i = next_char(str, i + 1, space_chars, true)
-- Read value
val, i = parse(str, i)
-- Set
res[key] = val
-- Next token
i = next_char(str, i, space_chars, true)
local chr = str:sub(i, i)
i = i + 1
if chr == "}" then break end
if chr ~= "," then decode_error(str, i, "expected '}' or ','") end
end
return res, i
end
local char_func_map = {
[ '"' ] = parse_string,
[ "0" ] = parse_number,
[ "1" ] = parse_number,
[ "2" ] = parse_number,
[ "3" ] = parse_number,
[ "4" ] = parse_number,
[ "5" ] = parse_number,
[ "6" ] = parse_number,
[ "7" ] = parse_number,
[ "8" ] = parse_number,
[ "9" ] = parse_number,
[ "-" ] = parse_number,
[ "t" ] = parse_literal,
[ "f" ] = parse_literal,
[ "n" ] = parse_literal,
[ "[" ] = parse_array,
[ "{" ] = parse_object,
}
parse = function(str, idx)
local chr = str:sub(idx, idx)
local f = char_func_map[chr]
if f then
return f(str, idx)
end
decode_error(str, idx, "unexpected character '" .. chr .. "'")
end
function json.decode(str)
if type(str) ~= "string" then
error("expected argument of type string, got " .. type(str))
end
local res, idx = parse(str, next_char(str, 1, space_chars, true))
idx = next_char(str, idx, space_chars, true)
if idx <= #str then
decode_error(str, idx, "trailing garbage")
end
return res
end
return json

View File

@ -0,0 +1,2 @@
local orientation = Quaternion()
print( orientation, orientation.x )