From c0dccc8401ba809d6288fb434f0fa49be0e96e3b Mon Sep 17 00:00:00 2001 From: Nitwel Date: Fri, 5 Apr 2024 19:29:18 +0200 Subject: [PATCH 01/10] make miniature view separate --- app/content/entities/sensor/sensor.gd | 14 ++ app/content/system/house/house.gd | 43 +--- app/content/system/house/house.tscn | 5 +- .../system/house/mini/mini_view_options.gd | 3 + app/content/system/house/mini/mini_wall.tres | 19 ++ .../house/mini/mini_wall_shader.gdshader | 39 ++++ app/content/system/house/mini/miniature.gd | 84 ++++++++ app/content/system/house/mini/miniature.tscn | 24 +++ app/content/system/house/room/room.gd | 73 +------ app/content/system/house/room/room.tscn | 6 +- app/content/system/house/room/states/mini.gd | 41 ---- app/content/system/house/room/states/view.gd | 48 +---- .../house/room/{walls.tres => wall.tres} | 0 app/content/system/house/room/walls_mini.tres | 6 - app/content/ui/menu/edit/edit_menu.gd | 9 + app/content/ui/menu/view/view_menu.gd | 3 +- app/lib/utils/mesh/construct_room_mesh.gd | 194 ++++++++++++++++++ 17 files changed, 408 insertions(+), 203 deletions(-) create mode 100644 app/content/system/house/mini/mini_view_options.gd create mode 100644 app/content/system/house/mini/mini_wall.tres create mode 100644 app/content/system/house/mini/mini_wall_shader.gdshader create mode 100644 app/content/system/house/mini/miniature.gd create mode 100644 app/content/system/house/mini/miniature.tscn delete mode 100644 app/content/system/house/room/states/mini.gd rename app/content/system/house/room/{walls.tres => wall.tres} (100%) delete mode 100644 app/content/system/house/room/walls_mini.tres create mode 100644 app/lib/utils/mesh/construct_room_mesh.gd diff --git a/app/content/entities/sensor/sensor.gd b/app/content/entities/sensor/sensor.gd index 998c0e6..c7c49f5 100644 --- a/app/content/entities/sensor/sensor.gd +++ b/app/content/entities/sensor/sensor.gd @@ -5,6 +5,8 @@ const Entity = preload ("../entity.gd") @onready var label: Label3D = $Label @onready var collision_shape = $CollisionShape3D +var sensor_data = {} + # Called when the node enters the scene tree for the first time. func _ready(): super() @@ -17,6 +19,9 @@ func _ready(): ) func set_text(stateInfo): + if stateInfo == null: + return + var text = stateInfo["state"] if stateInfo["attributes"]["friendly_name"] != null: @@ -25,6 +30,9 @@ func set_text(stateInfo): if stateInfo["attributes"].has("unit_of_measurement")&&stateInfo["attributes"]["unit_of_measurement"] != null: text += " " + stateInfo["attributes"]["unit_of_measurement"] + if stateInfo["attributes"].has("device_class"): + sensor_data[stateInfo["attributes"]["device_class"]] = stateInfo["state"] + label.text = text var font = label.get_font() @@ -35,3 +43,9 @@ func set_text(stateInfo): collision_shape.shape.size.x = size.x * label.pixel_size * 0.5 collision_shape.shape.size.y = size.y * label.pixel_size * 0.25 + +func get_sensor_data(type: String): + if sensor_data.has(type) == false: + return null + + return sensor_data[type] diff --git a/app/content/system/house/house.gd b/app/content/system/house/house.gd index 2edfeb5..9d8392b 100644 --- a/app/content/system/house/house.gd +++ b/app/content/system/house/house.gd @@ -6,13 +6,10 @@ const RoomType = preload ("./room/room.gd") @onready var levels = $Levels @onready var collision_shape = $Levels/CollisionShape3D @onready var align_reference = $AlignReference +@onready var mini_view = $Miniature var fixing_reference: bool = false var editing_room: RoomType = null -var mini_view: bool = false: - set(value): - mini_view = value - update_mini_view() func _ready(): Store.house.on_loaded.connect(func(): @@ -198,44 +195,6 @@ func create_entity_in(entity_id: String, room_name: String): return entity -func update_mini_view(): - collision_shape.disabled = !mini_view - - var tween = create_tween() - tween.set_parallel(true) - tween.set_trans(Tween.TRANS_CUBIC) - - if mini_view: - var aabb = get_level_aabb(0) - aabb.position.y = -0.03 - aabb.size.y = 0.06 - var center = aabb.position + aabb.size / 2.0 - - collision_shape.global_position = center - collision_shape.shape.size = aabb.size - - var camera = get_node("/root/Main/XROrigin3D/XRCamera3D") - var camera_position = camera.global_position - var camera_direction = -camera.global_transform.basis.z - - camera_position.y *= 0.5 - camera_direction.y = 0.0 - - var target_position = camera_position + camera_direction.normalized() * 0.2 - var new_position = target_position - center * 0.1 - tween.tween_property(levels, "global_position", new_position, 0.5) - tween.tween_property(levels, "scale", Vector3(0.1, 0.1, 0.1), 0.5) - - for room in get_rooms(0): - room.state_machine.change_to("Mini") - else: - tween.tween_property(levels, "global_position", Vector3(0, 0, 0), 0.5) - tween.tween_property(levels, "scale", Vector3(1.0, 1.0, 1.0), 0.5) - await tween.finished - - for room in get_rooms(0): - room.state_machine.change_to("View") - func edit_reference(): fixing_reference = false align_reference.visible = true diff --git a/app/content/system/house/house.tscn b/app/content/system/house/house.tscn index b17ab66..aad1919 100644 --- a/app/content/system/house/house.tscn +++ b/app/content/system/house/house.tscn @@ -1,8 +1,9 @@ -[gd_scene load_steps=5 format=3 uid="uid://cbemihbxkd4ll"] +[gd_scene load_steps=6 format=3 uid="uid://cbemihbxkd4ll"] [ext_resource type="Script" path="res://content/system/house/house.gd" id="1_p8amj"] [ext_resource type="Script" path="res://content/functions/movable.gd" id="2_w1auk"] [ext_resource type="PackedScene" uid="uid://jls16btb8nko" path="res://content/system/house/align_reference.tscn" id="3_e1tcn"] +[ext_resource type="PackedScene" uid="uid://ds60i5n211hi3" path="res://content/system/house/mini/miniature.tscn" id="4_qjbly"] [sub_resource type="BoxShape3D" id="BoxShape3D_x81up"] @@ -25,3 +26,5 @@ lock_rotation = true [node name="AlignReference" parent="." instance=ExtResource("3_e1tcn")] visible = false disabled = true + +[node name="Miniature" parent="." instance=ExtResource("4_qjbly")] diff --git a/app/content/system/house/mini/mini_view_options.gd b/app/content/system/house/mini/mini_view_options.gd new file mode 100644 index 0000000..ab7dc6b --- /dev/null +++ b/app/content/system/house/mini/mini_view_options.gd @@ -0,0 +1,3 @@ +extends Node3D + +const mini_wall_shader: ShaderMaterial = preload ("./mini_wall.tres") diff --git a/app/content/system/house/mini/mini_wall.tres b/app/content/system/house/mini/mini_wall.tres new file mode 100644 index 0000000..05daa0c --- /dev/null +++ b/app/content/system/house/mini/mini_wall.tres @@ -0,0 +1,19 @@ +[gd_resource type="ShaderMaterial" load_steps=4 format=3 uid="uid://bcfcough6ucvc"] + +[ext_resource type="Shader" path="res://content/system/house/mini/mini_wall_shader.gdshader" id="1_sbr3e"] + +[sub_resource type="Gradient" id="Gradient_2jwis"] +interpolation_color_space = 2 +offsets = PackedFloat32Array(0.00280112, 1) +colors = PackedColorArray(0, 0.558935, 0.886772, 1, 0.999396, 0, 0.058647, 1) + +[sub_resource type="GradientTexture1D" id="GradientTexture1D_rrsal"] +gradient = SubResource("Gradient_2jwis") + +[resource] +render_priority = 0 +shader = ExtResource("1_sbr3e") +shader_parameter/data = PackedFloat32Array() +shader_parameter/data_size = 0 +shader_parameter/min_max_data = null +shader_parameter/color_gradient = SubResource("GradientTexture1D_rrsal") diff --git a/app/content/system/house/mini/mini_wall_shader.gdshader b/app/content/system/house/mini/mini_wall_shader.gdshader new file mode 100644 index 0000000..66bb686 --- /dev/null +++ b/app/content/system/house/mini/mini_wall_shader.gdshader @@ -0,0 +1,39 @@ +shader_type spatial; +render_mode blend_mix, depth_draw_opaque, cull_disabled, diffuse_lambert, specular_schlick_ggx, unshaded; + +uniform vec4 data[100]; +uniform int data_size: hint_range(0, 100, 1); +uniform vec2 min_max_data; +uniform sampler2D color_gradient; + +varying vec3 color; + + + +void vertex() { + // Calculate Global Coordinates + vec3 world_position = (MODEL_MATRIX * vec4(VERTEX, 1.0)).xyz; + + color = vec3(1.0, 1.0, 1.0); + vec2 distances[100]; + float dist_sum = 0.0; + + if(data_size > 0) { + for(int i = 0; i < data_size; i++) { + float delta = 1.0 / distance(data[i].xyz, world_position); + + distances[i] = vec2(delta, data[i].w); + dist_sum += delta; + } + + for(int i = 0; i < data_size; i++) { + float average = distances[i].x / dist_sum * distances[i].y; + color.xyz = texture(color_gradient, vec2(average, 0)).xyz; + } + } +} + +void fragment() { + ALBEDO = vec3(color.xyz); + ALPHA = 0.3; +} diff --git a/app/content/system/house/mini/miniature.gd b/app/content/system/house/mini/miniature.gd new file mode 100644 index 0000000..0a63fd4 --- /dev/null +++ b/app/content/system/house/mini/miniature.gd @@ -0,0 +1,84 @@ +extends Node3D + +const ConstructRoomMesh = preload ("res://lib/utils/mesh/construct_room_mesh.gd") +const wall_material = preload ("./mini_wall.tres") + +@onready var walls_mesh = $WallsMesh +@onready var floor_mesh = $FloorMesh +@onready var collision_shape = $CollisionShape3D +@onready var toggle_heatmap = $HeatmapButton + +var enabled = true: + set(value): + enabled = value + update() + +func _ready(): + update() + + if Store.house.is_loaded() == false: + await Store.house.on_loaded + + var room = Store.house.rooms[0] + + var corners = room.corners + var height = room.height + + walls_mesh.mesh = ConstructRoomMesh.generate_wall_mesh_grid(corners, height) + floor_mesh.mesh = ConstructRoomMesh.generate_ceiling_mesh_grid(corners) + + walls_mesh.material_override = wall_material + floor_mesh.material_override = wall_material + + active = true + update_data(0.0) + + toggle_heatmap.on_button_down.connect(func(): + active=true + EventSystem.on_slow_tick.connect(update_data) + ) + + toggle_heatmap.on_button_up.connect(func(): + wall_material.set_shader_parameter("data", []) + wall_material.set_shader_parameter("data_size", 0) + active=false + EventSystem.on_slow_tick.disconnect(update_data) + ) + +func update(): + walls_mesh.visible = enabled + floor_mesh.visible = enabled + collision_shape.disabled = not enabled + +const SensorEntity = preload ("res://content/entities/sensor/sensor.gd") + +var active: bool = false + +func update_data(delta: float) -> void: + var data_list = [] + var min_max_data + + for room in House.body.get_rooms(0): + for entity in room.get_node("Entities").get_children(): + if entity is SensorEntity: + var sensor = entity as SensorEntity + var data = sensor.get_sensor_data("temperature") + if data == null: + continue + + var sensor_pos = sensor.global_position + + if min_max_data == null: + min_max_data = Vector2(float(data), float(data)) + else: + min_max_data.x = min(min_max_data.x, float(data)) + min_max_data.y = max(min_max_data.y, float(data)) + + data_list.append(Vector4(sensor_pos.x, sensor_pos.y, sensor_pos.z, float(data))) + + for data in data_list: + data.w = (data.w - min_max_data.x) / (min_max_data.y - min_max_data.x) + + wall_material.set_shader_parameter("data", data_list) + wall_material.set_shader_parameter("min_max_data", min_max_data) + wall_material.set_shader_parameter("data_size", data_list.size()) diff --git a/app/content/system/house/mini/miniature.tscn b/app/content/system/house/mini/miniature.tscn new file mode 100644 index 0000000..a48b30b --- /dev/null +++ b/app/content/system/house/mini/miniature.tscn @@ -0,0 +1,24 @@ +[gd_scene load_steps=5 format=3 uid="uid://ds60i5n211hi3"] + +[ext_resource type="Script" path="res://content/system/house/mini/miniature.gd" id="1_b53yn"] +[ext_resource type="Script" path="res://content/functions/movable.gd" id="2_x7oed"] +[ext_resource type="PackedScene" uid="uid://bsjqdvkt0u87c" path="res://content/ui/components/button/button.tscn" id="3_tgdcf"] + +[sub_resource type="BoxShape3D" id="BoxShape3D_bckw3"] + +[node name="Miniature" type="StaticBody3D"] +script = ExtResource("1_b53yn") + +[node name="WallsMesh" type="MeshInstance3D" parent="."] + +[node name="FloorMesh" type="MeshInstance3D" parent="."] + +[node name="CollisionShape3D" type="CollisionShape3D" parent="."] +shape = SubResource("BoxShape3D_bckw3") + +[node name="Movable" type="Node" parent="."] +script = ExtResource("2_x7oed") + +[node name="HeatmapButton" parent="." instance=ExtResource("3_tgdcf")] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0.25, 0.5, 0.48) +toggleable = true diff --git a/app/content/system/house/room/room.gd b/app/content/system/house/room/room.gd index 7c76b8f..e9f1107 100644 --- a/app/content/system/house/room/room.gd +++ b/app/content/system/house/room/room.gd @@ -1,5 +1,7 @@ extends Node3D +const ConstructRoomMesh = preload ("res://lib/utils/mesh/construct_room_mesh.gd") + @onready var wall_corners = $Ceiling/WallCorners @onready var wall_edges = $Ceiling/WallEdges @onready var wall_mesh: MeshInstance3D = $WallMesh @@ -55,75 +57,12 @@ func get_aabb(): return AABB(to_global(min_pos), to_global(max_pos) - to_global(min_pos)) static func generate_wall_mesh(room_store: Dictionary): - if room_store.corners.size() < 2: - return null + var corners = room_store.corners + var height = room_store.height - var st = SurfaceTool.new() - var wall_up = Vector3.UP * room_store.height - - st.begin(Mesh.PRIMITIVE_TRIANGLE_STRIP) - - for corner in room_store.corners: - var corner3D = Vector3(corner.x, 0, corner.y) - - st.add_vertex(corner3D) - st.add_vertex(corner3D + wall_up) - - var first_corner = Vector3(room_store.corners[0].x, 0, room_store.corners[0].y) - - st.add_vertex(first_corner) - st.add_vertex(first_corner + wall_up) - - st.index() - st.generate_normals() - st.generate_tangents() - var mesh = st.commit() - - return mesh + return ConstructRoomMesh.generate_wall_mesh_grid(corners, height) static func generate_ceiling_mesh(room_store: Dictionary): - - var points: PackedVector2Array = PackedVector2Array() - var edges: PackedInt32Array = PackedInt32Array() - var triangles: PackedInt32Array - var corners = room_store.corners - if corners.size() < 3: - return null - - for i in range(corners.size()): - var corner = corners[i] - points.append(Vector2(corner.x, corner.y)) - edges.append(i) - edges.append((i + 1) % corners.size()) - - var cdt: ConstrainedTriangulation = ConstrainedTriangulation.new() - - cdt.init(true, true, 0.1) - - cdt.insert_vertices(points) - cdt.insert_edges(edges) - - cdt.erase_outer_triangles() - - points = cdt.get_all_vertices() - triangles = cdt.get_all_triangles() - - var st = SurfaceTool.new() - - st.begin(Mesh.PRIMITIVE_TRIANGLES) - - for i in range(points.size()): - st.add_vertex(Vector3(points[i].x, 0, points[i].y)) - - for i in range(triangles.size()): - st.add_index(triangles[i]) - - st.index() - st.generate_normals() - st.generate_tangents() - - var mesh = st.commit() - - return mesh + return ConstructRoomMesh.generate_ceiling_mesh_grid(corners) diff --git a/app/content/system/house/room/room.tscn b/app/content/system/house/room/room.tscn index 36a4f70..d222beb 100644 --- a/app/content/system/house/room/room.tscn +++ b/app/content/system/house/room/room.tscn @@ -1,9 +1,8 @@ -[gd_scene load_steps=9 format=3 uid="uid://bswgmclohuqui"] +[gd_scene load_steps=8 format=3 uid="uid://bswgmclohuqui"] [ext_resource type="Script" path="res://content/system/house/room/room.gd" id="1_fccq0"] [ext_resource type="Script" path="res://content/functions/clickable.gd" id="1_ugebq"] [ext_resource type="Script" path="res://lib/utils/state_machine/state_machine.gd" id="4_nbbo6"] -[ext_resource type="Script" path="res://content/system/house/room/states/mini.gd" id="6_g4qca"] [ext_resource type="Script" path="res://content/system/house/room/states/view.gd" id="6_g066t"] [ext_resource type="Script" path="res://content/system/house/room/states/edit.gd" id="7_ap14h"] @@ -57,7 +56,4 @@ script = ExtResource("6_g066t") [node name="Edit" type="Node" parent="StateMachine"] script = ExtResource("7_ap14h") -[node name="Mini" type="Node" parent="StateMachine"] -script = ExtResource("6_g4qca") - [node name="Entities" type="Node3D" parent="."] diff --git a/app/content/system/house/room/states/mini.gd b/app/content/system/house/room/states/mini.gd deleted file mode 100644 index 394db7a..0000000 --- a/app/content/system/house/room/states/mini.gd +++ /dev/null @@ -1,41 +0,0 @@ -extends RoomState - -const RoomState = preload("./room_state.gd") -const walls_mini_material = preload("../walls_mini.tres") -const walls_material = preload("../walls.tres") - -func _on_enter(): - room.wall_mesh.visible = true - room.ceiling_mesh.visible = false - room.wall_mesh.material_override = walls_mini_material - room.room_ceiling.get_node("CollisionShape3D").disabled = true - room.room_floor.get_node("CollisionShape3D").disabled = true - - for collision in room.wall_collisions.get_children(): - collision.get_child(0).disabled = true - - for corner in room.wall_corners.get_children(): - corner.get_node("CollisionShape3D").disabled = true - - for edge in room.wall_edges.get_children(): - edge.get_node("CollisionShape3D").disabled = true - - - -func _on_leave(): - room.wall_mesh.visible = false - room.ceiling_mesh.visible = false - room.wall_mesh.material_override = walls_material - room.room_ceiling.get_node("CollisionShape3D").disabled = false - room.room_floor.get_node("CollisionShape3D").disabled = false - - for collision in room.wall_collisions.get_children(): - collision.get_child(0).disabled = false - - for corner in room.wall_corners.get_children(): - corner.get_node("CollisionShape3D").disabled = false - - for edge in room.wall_edges.get_children(): - edge.get_node("CollisionShape3D").disabled = false - - diff --git a/app/content/system/house/room/states/view.gd b/app/content/system/house/room/states/view.gd index ade276a..e21c7ec 100644 --- a/app/content/system/house/room/states/view.gd +++ b/app/content/system/house/room/states/view.gd @@ -28,16 +28,16 @@ func _on_enter(): ceiling_shape.shape = room.ceiling_mesh.mesh.create_trimesh_shape() floor_shape.shape = room.ceiling_mesh.mesh.create_trimesh_shape() ceiling_shape.shape.backface_collision = true - - var collisions = generate_collision() - for collision in collisions: - var static_body = StaticBody3D.new() - static_body.set_collision_layer_value(4, true) - static_body.set_collision_layer_value(5, true) - static_body.collision_mask = 0 - static_body.add_child(collision) - room.wall_collisions.add_child(static_body) + var collision = CollisionShape3D.new() + collision.shape = room.wall_mesh.mesh.create_trimesh_shape() + + var static_body = StaticBody3D.new() + static_body.set_collision_layer_value(4, true) + static_body.set_collision_layer_value(5, true) + static_body.collision_mask = 0 + static_body.add_child(collision) + room.wall_collisions.add_child(static_body) func _on_leave(): room.room_ceiling.get_node("CollisionShape3D").disabled = true @@ -46,33 +46,3 @@ func _on_leave(): for collision in room.wall_collisions.get_children(): collision.queue_free() await collision.tree_exited - -func generate_collision(): - var room_store = Store.house.get_room(room.name) - - var collision_shapes: Array[CollisionShape3D] = [] - - var corners = room_store.corners - - for i in range(corners.size()): - var corner = Vector3(corners[i].x, 0, corners[i].y) - var next_corner_index = (i + 1) % corners.size() - var next_corner = Vector3(corners[next_corner_index].x, 0, corners[next_corner_index].y) - - var shape = BoxShape3D.new() - shape.size = Vector3((next_corner - corner).length(), room_store.height, 0.04) - - var transform = Transform3D() - var back_vector = (corner - next_corner).cross(Vector3.UP).normalized() * shape.size.z / 2 - - transform.basis = Basis((next_corner - corner).normalized(), Vector3.UP, back_vector.normalized()) - transform.origin = corner + (next_corner - corner) / 2 + back_vector + Vector3.UP * shape.size.y / 2 - - var collision_shape = CollisionShape3D.new() - - collision_shape.shape = shape - collision_shape.transform = transform - - collision_shapes.append(collision_shape) - - return collision_shapes diff --git a/app/content/system/house/room/walls.tres b/app/content/system/house/room/wall.tres similarity index 100% rename from app/content/system/house/room/walls.tres rename to app/content/system/house/room/wall.tres diff --git a/app/content/system/house/room/walls_mini.tres b/app/content/system/house/room/walls_mini.tres deleted file mode 100644 index ead6994..0000000 --- a/app/content/system/house/room/walls_mini.tres +++ /dev/null @@ -1,6 +0,0 @@ -[gd_resource type="StandardMaterial3D" format=3 uid="uid://dxyuncqxagt28"] - -[resource] -transparency = 1 -cull_mode = 2 -albedo_color = Color(1, 1, 1, 0.47451) diff --git a/app/content/ui/menu/edit/edit_menu.gd b/app/content/ui/menu/edit/edit_menu.gd index 9769d8c..84fa240 100644 --- a/app/content/ui/menu/edit/edit_menu.gd +++ b/app/content/ui/menu/edit/edit_menu.gd @@ -32,6 +32,15 @@ func _enter_tree(): func load_devices(): if devices.size() == 0: devices = await HomeApi.get_devices() + devices.sort_custom(func(a, b): + return a.values()[0]["name"].to_lower() < b.values()[0]["name"].to_lower() + ) + + for device in devices: + device.values()[0]["entities"].sort_custom(func(a, b): + return a.to_lower() < b.to_lower() + ) + render() HomeApi.on_disconnect.connect(func(): diff --git a/app/content/ui/menu/view/view_menu.gd b/app/content/ui/menu/view/view_menu.gd index 11fa1b9..4324da8 100644 --- a/app/content/ui/menu/view/view_menu.gd +++ b/app/content/ui/menu/view/view_menu.gd @@ -7,6 +7,5 @@ func _ready(): background.visible = false mini_view.on_button_down.connect(func(): - House.body.mini_view = !House.body.mini_view + House.body.mini_view.enabled=!House.body.mini_view.enabled ) - diff --git a/app/lib/utils/mesh/construct_room_mesh.gd b/app/lib/utils/mesh/construct_room_mesh.gd new file mode 100644 index 0000000..602cfc2 --- /dev/null +++ b/app/lib/utils/mesh/construct_room_mesh.gd @@ -0,0 +1,194 @@ +static func generate_wall_mesh(corners, height): + if corners.size() < 3: + return null + + var st = SurfaceTool.new() + var wall_up = Vector3.UP * height + + st.begin(Mesh.PRIMITIVE_TRIANGLE_STRIP) + + for corner in corners: + var corner3D = Vector3(corner.x, 0, corner.y) + + st.add_vertex(corner3D) + st.add_vertex(corner3D + wall_up) + + var first_corner = Vector3(corners[0].x, 0, corners[0].y) + + st.add_vertex(first_corner) + st.add_vertex(first_corner + wall_up) + + st.index() + st.generate_normals() + st.generate_tangents() + var mesh = st.commit() + + return mesh + +static func generate_ceiling_mesh(corners): + var points: PackedVector2Array = PackedVector2Array() + var edges: PackedInt32Array = PackedInt32Array() + var triangles: PackedInt32Array + + if corners.size() < 3: + return null + + for i in range(corners.size()): + var corner = corners[i] + points.append(Vector2(corner.x, corner.y)) + edges.append(i) + edges.append((i + 1) % corners.size()) + + var cdt: ConstrainedTriangulation = ConstrainedTriangulation.new() + + cdt.init(true, true, 0.1) + + cdt.insert_vertices(points) + cdt.insert_edges(edges) + + cdt.erase_outer_triangles() + + points = cdt.get_all_vertices() + triangles = cdt.get_all_triangles() + + return _create_mesh(points, triangles) + +static func generate_wall_mesh_grid(corners, height, grid: Vector2=Vector2(0.1, 0.1)): + if corners.size() < 3: + return null + + var st = SurfaceTool.new() + + st.begin(Mesh.PRIMITIVE_TRIANGLES) + + for corner_i in range(corners.size()): + var corner = Vector3(corners[corner_i].x, 0, corners[corner_i].y) + var next_index = (corner_i + 1) % corners.size() + var next_corner = Vector3(corners[next_index].x, 0, corners[next_index].y) + + var steps = ceil(Vector2((next_corner - corner).length() / grid.x, height / grid.y)) + + var forward_dir = (next_corner - corner).normalized() * grid.x + var up_dir = Vector3.UP * grid.y + + var close_distance = Vector2(1, 1) + + for y in range(0, steps.y): + + close_distance.x = 1 + + if y == steps.y - 1: + close_distance.y = fmod(height, grid.y) / grid.y + print(close_distance.y) + + for x in range(0, steps.x): + var point = corner + forward_dir * x + Vector3.UP * grid.y * y + + if x == steps.x - 1: + close_distance.x = fmod(corner.distance_to(next_corner), grid.x) / grid.x + + st.add_vertex(point) + st.add_vertex(point + forward_dir * close_distance.x) + st.add_vertex(point + up_dir * close_distance.y) + + st.add_vertex(point + forward_dir * close_distance.x) + st.add_vertex(point + forward_dir * close_distance.x + up_dir * close_distance.y) + st.add_vertex(point + up_dir * close_distance.y) + + st.index() + st.generate_normals() + st.generate_tangents() + var mesh = st.commit() + + return mesh + +static func generate_ceiling_mesh_grid(corners, grid: Vector2=Vector2(0.1, 0.1)): + var points: PackedVector2Array = PackedVector2Array() + var edges: PackedInt32Array = PackedInt32Array() + var triangles: PackedInt32Array + + if corners.size() < 3: + return null + + var min_val = Vector2(corners[0]) + var max_val = Vector2(corners[0]) + + for i in range(corners.size()): + var corner = corners[i] + + min_val.x = min(min_val.x, corner.x) + min_val.y = min(min_val.y, corner.y) + max_val.x = max(max_val.x, corner.x) + max_val.y = max(max_val.y, corner.y) + + points.append(Vector2(corner.x, corner.y)) + edges.append(i) + edges.append((i + 1) % corners.size()) + + var size = max_val - min_val + + ## Fill points insde the polygon + for y in range(1, int(size.y / grid.y)): + var x_intersections: Array[float] = [] + + var y_start = Vector2(min_val.x, min_val.y + y * grid.y) + var y_end = Vector2(max_val.x, min_val.y + y * grid.y) + + for i in range(corners.size()): + var a = corners[i] + var b = corners[(i + 1) % corners.size()] + + var result = Geometry2D.segment_intersects_segment(a, b, y_start, y_end) + + if result != null: + x_intersections.append(result.x) + + var intersection_counter = 0 + + x_intersections.sort() + + for x in range(1, int(size.x / grid.x)): + var point = min_val + Vector2(x * grid.x, y * grid.y) + + for i in range(intersection_counter, x_intersections.size()): + if x_intersections[i] < point.x: + intersection_counter += 1 + + var color = Color(1, 1, 0) + + if intersection_counter % 2 == 1: + color = Color(1, 0, 1) + points.append(point) + + var cdt: ConstrainedTriangulation = ConstrainedTriangulation.new() + + cdt.init(true, true, 0.1) + + cdt.insert_vertices(points) + cdt.insert_edges(edges) + + cdt.erase_outer_triangles() + + points = cdt.get_all_vertices() + triangles = cdt.get_all_triangles() + + return _create_mesh(points, triangles) + +static func _create_mesh(points: PackedVector2Array, triangles: PackedInt32Array): + var st = SurfaceTool.new() + + st.begin(Mesh.PRIMITIVE_TRIANGLES) + + for i in range(points.size()): + st.add_vertex(Vector3(points[i].x, 0, points[i].y)) + + for i in range(triangles.size()): + st.add_index(triangles[i]) + + st.index() + st.generate_normals() + st.generate_tangents() + + var mesh = st.commit() + + return mesh \ No newline at end of file From 586ea20d1aad4d6d8c8d56e12b565120c55bac1d Mon Sep 17 00:00:00 2001 From: Nitwel Date: Sun, 7 Apr 2024 14:17:52 +0200 Subject: [PATCH 02/10] finish heat map shader --- app/content/system/house/mini/mini_wall.tres | 8 ++-- .../house/mini/mini_wall_shader.gdshader | 39 +++++++++++++++---- app/content/system/house/mini/miniature.gd | 30 +++++++------- app/content/system/house/mini/miniature.tscn | 21 ++++++---- app/lib/utils/mesh/construct_room_mesh.gd | 15 +++++++ 5 files changed, 80 insertions(+), 33 deletions(-) diff --git a/app/content/system/house/mini/mini_wall.tres b/app/content/system/house/mini/mini_wall.tres index 05daa0c..ea81d20 100644 --- a/app/content/system/house/mini/mini_wall.tres +++ b/app/content/system/house/mini/mini_wall.tres @@ -4,8 +4,10 @@ [sub_resource type="Gradient" id="Gradient_2jwis"] interpolation_color_space = 2 -offsets = PackedFloat32Array(0.00280112, 1) -colors = PackedColorArray(0, 0.558935, 0.886772, 1, 0.999396, 0, 0.058647, 1) +offsets = PackedFloat32Array(0.00840336, 0.1, 0.4375, 0.5625, 1) +colors = PackedColorArray(0.533333, 0, 1, 1, 0, 0.45, 1, 1, 0, 0.95, 1, 1, 0.983333, 1, 0, 1, 0.999396, 0, 0.058647, 1) +metadata/_snap_enabled = true +metadata/_snap_count = 16 [sub_resource type="GradientTexture1D" id="GradientTexture1D_rrsal"] gradient = SubResource("Gradient_2jwis") @@ -15,5 +17,5 @@ render_priority = 0 shader = ExtResource("1_sbr3e") shader_parameter/data = PackedFloat32Array() shader_parameter/data_size = 0 -shader_parameter/min_max_data = null +shader_parameter/alpha = 0.3 shader_parameter/color_gradient = SubResource("GradientTexture1D_rrsal") diff --git a/app/content/system/house/mini/mini_wall_shader.gdshader b/app/content/system/house/mini/mini_wall_shader.gdshader index 66bb686..0af72f6 100644 --- a/app/content/system/house/mini/mini_wall_shader.gdshader +++ b/app/content/system/house/mini/mini_wall_shader.gdshader @@ -3,32 +3,55 @@ render_mode blend_mix, depth_draw_opaque, cull_disabled, diffuse_lambert, specul uniform vec4 data[100]; uniform int data_size: hint_range(0, 100, 1); -uniform vec2 min_max_data; +uniform float alpha: hint_range(0.0, 1.0, 0.1) = 0.3; uniform sampler2D color_gradient; varying vec3 color; +float simple_weight(int index, vec3 world_pos, float p) { + return 1.0 / pow(distance(data[index].xyz, world_pos), p); +} +float sphere_weight(int index, vec3 world_pos, float r) { + float dist = distance(data[index].xyz, world_pos); + return pow(max(0, r - dist) / (r * dist), 2); +} void vertex() { // Calculate Global Coordinates vec3 world_position = (MODEL_MATRIX * vec4(VERTEX, 1.0)).xyz; color = vec3(1.0, 1.0, 1.0); - vec2 distances[100]; + float distances[100]; float dist_sum = 0.0; + float data_sum = 0.0; + + float closest_dist = -1.0; + int closest_index = 0; if(data_size > 0) { + closest_dist = distance(data[0].xyz, world_position); + + // Inverse distance weighting using Shepard's method for(int i = 0; i < data_size; i++) { - float delta = 1.0 / distance(data[i].xyz, world_position); + distances[i] = sphere_weight(i, world_position, 5.0); + dist_sum += distances[i]; + data_sum += distances[i] * data[i].w; - distances[i] = vec2(delta, data[i].w); - dist_sum += delta; + float dist = distance(data[i].xyz, world_position); + + if(dist < closest_dist) { + closest_dist = dist; + closest_index = i; + } } - for(int i = 0; i < data_size; i++) { - float average = distances[i].x / dist_sum * distances[i].y; - color.xyz = texture(color_gradient, vec2(average, 0)).xyz; + float value = (1.0 / dist_sum) * data_sum; + + if( value > 0.0 || value < 1.0) { + color.xyz = texture(color_gradient, vec2(value, 0)).xyz; + } else { + color.xyz = texture(color_gradient, vec2(data[closest_index].w, 0)).xyz; } } } diff --git a/app/content/system/house/mini/miniature.gd b/app/content/system/house/mini/miniature.gd index 0a63fd4..66004c9 100644 --- a/app/content/system/house/mini/miniature.gd +++ b/app/content/system/house/mini/miniature.gd @@ -3,11 +3,14 @@ extends Node3D const ConstructRoomMesh = preload ("res://lib/utils/mesh/construct_room_mesh.gd") const wall_material = preload ("./mini_wall.tres") -@onready var walls_mesh = $WallsMesh -@onready var floor_mesh = $FloorMesh -@onready var collision_shape = $CollisionShape3D +@onready var walls_mesh = $Body/Model/WallsMesh +@onready var floor_mesh = $Body/Model/FloorMesh +@onready var collision_shape = $Body/CollisionShape3D @onready var toggle_heatmap = $HeatmapButton +# var temperature_scale := Vector2( - 20.0, 60.0) +var temperature_scale := Vector2(22.0, 25.0) + var enabled = true: set(value): enabled = value @@ -19,6 +22,9 @@ func _ready(): if Store.house.is_loaded() == false: await Store.house.on_loaded + if Store.house.rooms.size() == 0: + return + var room = Store.house.rooms[0] var corners = room.corners @@ -31,7 +37,7 @@ func _ready(): floor_mesh.material_override = wall_material active = true - update_data(0.0) + EventSystem.on_slow_tick.connect(update_data) toggle_heatmap.on_button_down.connect(func(): active=true @@ -56,7 +62,6 @@ var active: bool = false func update_data(delta: float) -> void: var data_list = [] - var min_max_data for room in House.body.get_rooms(0): for entity in room.get_node("Entities").get_children(): @@ -68,17 +73,14 @@ func update_data(delta: float) -> void: var sensor_pos = sensor.global_position - if min_max_data == null: - min_max_data = Vector2(float(data), float(data)) - else: - min_max_data.x = min(min_max_data.x, float(data)) - min_max_data.y = max(min_max_data.y, float(data)) - data_list.append(Vector4(sensor_pos.x, sensor_pos.y, sensor_pos.z, float(data))) - for data in data_list: - data.w = (data.w - min_max_data.x) / (min_max_data.y - min_max_data.x) + data_list = data_list.map(func(data: Vector4) -> Vector4: + data.w=(data.w - temperature_scale.x) / (temperature_scale.y - temperature_scale.x) + return data + ) + + print(data_list) wall_material.set_shader_parameter("data", data_list) - wall_material.set_shader_parameter("min_max_data", min_max_data) wall_material.set_shader_parameter("data_size", data_list.size()) diff --git a/app/content/system/house/mini/miniature.tscn b/app/content/system/house/mini/miniature.tscn index a48b30b..1ae4bd5 100644 --- a/app/content/system/house/mini/miniature.tscn +++ b/app/content/system/house/mini/miniature.tscn @@ -6,19 +6,24 @@ [sub_resource type="BoxShape3D" id="BoxShape3D_bckw3"] -[node name="Miniature" type="StaticBody3D"] +[node name="Miniature" type="Node3D"] script = ExtResource("1_b53yn") -[node name="WallsMesh" type="MeshInstance3D" parent="."] +[node name="HeatmapButton" parent="." instance=ExtResource("3_tgdcf")] +toggleable = true -[node name="FloorMesh" type="MeshInstance3D" parent="."] +[node name="Body" type="StaticBody3D" parent="."] -[node name="CollisionShape3D" type="CollisionShape3D" parent="."] +[node name="CollisionShape3D" type="CollisionShape3D" parent="Body"] shape = SubResource("BoxShape3D_bckw3") -[node name="Movable" type="Node" parent="."] +[node name="Movable" type="Node" parent="Body"] script = ExtResource("2_x7oed") -[node name="HeatmapButton" parent="." instance=ExtResource("3_tgdcf")] -transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0.25, 0.5, 0.48) -toggleable = true +[node name="Model" type="Node3D" parent="Body"] + +[node name="WallsMesh" type="MeshInstance3D" parent="Body/Model"] +skeleton = NodePath("../../..") + +[node name="FloorMesh" type="MeshInstance3D" parent="Body/Model"] +skeleton = NodePath("../../..") diff --git a/app/lib/utils/mesh/construct_room_mesh.gd b/app/lib/utils/mesh/construct_room_mesh.gd index 602cfc2..b0045ce 100644 --- a/app/lib/utils/mesh/construct_room_mesh.gd +++ b/app/lib/utils/mesh/construct_room_mesh.gd @@ -127,6 +127,21 @@ static func generate_ceiling_mesh_grid(corners, grid: Vector2=Vector2(0.1, 0.1)) var size = max_val - min_val + # Subdivide edges to grid + for i in range(corners.size()): + var corner = corners[i] + var next_index = (i + 1) % corners.size() + var next_corner = corners[next_index] + + var steps = ceil(Vector2((next_corner - corner).length() / grid.x, size.y / grid.y)) + + var forward_dir = (next_corner - corner).normalized() * grid.x + + for x in range(1, steps.x): + var point = corner + forward_dir * x + + points.append(Vector2(point.x, point.y)) + ## Fill points insde the polygon for y in range(1, int(size.y / grid.y)): var x_intersections: Array[float] = [] From 6690b9b195e3f926102d1fba3238dc69a04b8785 Mon Sep 17 00:00:00 2001 From: Nitwel Date: Tue, 9 Apr 2024 15:30:23 +0200 Subject: [PATCH 03/10] add Rdot --- app/addons/rdot/Rdot.gd | 201 ++++++++++++++++++++++++++++++++ app/addons/rdot/array.gd | 13 +++ app/addons/rdot/computed.gd | 64 ++++++++++ app/addons/rdot/graph.gd | 225 ++++++++++++++++++++++++++++++++++++ app/addons/rdot/node.gd | 38 ++++++ app/addons/rdot/state.gd | 50 ++++++++ app/addons/rdot/store.gd | 37 ++++++ 7 files changed, 628 insertions(+) create mode 100644 app/addons/rdot/Rdot.gd create mode 100644 app/addons/rdot/array.gd create mode 100644 app/addons/rdot/computed.gd create mode 100644 app/addons/rdot/graph.gd create mode 100644 app/addons/rdot/node.gd create mode 100644 app/addons/rdot/state.gd create mode 100644 app/addons/rdot/store.gd diff --git a/app/addons/rdot/Rdot.gd b/app/addons/rdot/Rdot.gd new file mode 100644 index 0000000..7b52ca3 --- /dev/null +++ b/app/addons/rdot/Rdot.gd @@ -0,0 +1,201 @@ +class_name R + +static func state(value: Variant, options: Dictionary={}): + if value is Dictionary: + return store(value) + + return State.new(value, options) + +static func store(value: Dictionary): + return RdotStore.new(value) + +static func computed(computation: Callable, options: Dictionary={}): + return Computed.new(computation, options) + +## DIY overloading of +## bind(target, prop, value) +## bind(target, prop, value, watch_signal) +## bind(target, prop, store, key, watch_signal) +static func bind(target, prop, value, arg1=null, arg2=null): + if value is RdotStore: + return _bind_store(target, prop, value, arg1, arg2) + + if value is State or value is Computed: + return _bind_state(target, prop, value, arg1) + + assert(false, "Invalid arguments to bind, value must be a R.State or a RdotStore") + +static func _bind_store(target, prop, store: RdotStore, key, watch_signal=null): + store._access_property(key) + + return _bind_state(target, prop, store._proxied_value[key], watch_signal) + +static func _bind_state(target, prop, value, watch_signal=null): + var graph = RdotGraph.getInstance() + + var watch_c = func(new_value): + value.value = new_value + + var c = computed(func(_arg): + var oldValue=target.get(prop) + + if oldValue != value.value: + target.set(prop, value.value) + ) + + if watch_signal: + watch_signal.connect(watch_c) + + graph.watcher.watch([c]) + c.do_get() + + return func(): + graph.watcher.unwatch([c]) + if watch_signal: + watch_signal.disconnect(watch_c) + +static func effect(callback: Callable): + var graph = RdotGraph.getInstance() + + var deconstructor := Callable() + var c = computed(func(_arg): + if !deconstructor.is_null(): + deconstructor.call() + + var result=callback.call(_arg) + + if result is Callable: + deconstructor=result + ) + + graph.watcher.watch([c]) + c.do_get() + + return func(): + if !deconstructor.is_null(): + deconstructor.call() + + graph.watcher.unwatch([c]) + +class State: + var node: RdotState + var value = null: + get: + return do_get() + set(value): + do_set(value) + + func _init(value: Variant, options: Dictionary={}): + var ref = RdotState.createSignal(value) + var node = ref[1] + self.node = node + node.wrapper = self + + if !options.is_empty(): + var equals = options.get("equals") + + if !equals.is_null(): + node.equals = equals + + func do_get(): + return RdotState.signalGetFn.call(self.node) + + func do_set(value: Variant): + var graph = RdotGraph.getInstance() + + assert(graph.isInNotificationPhase() == false, "Writes to signals not permitted during Watcher callback") + + var ref = self.node + + RdotState.signalSetFn.call(ref, value) + +class Computed: + var node: RdotComputed + var value = null: + get: + return do_get() + set(value): + pass + + func _init(computation: Callable, options: Dictionary={}): + var ref = RdotComputed.createdComputed(computation) + var node = ref[1] + node.consumerAllowSignalWrites = true + self.node = node + node.wrapper = self + + if options: + var equals = options.get("equals") + + if !equals.is_null(): + node.equals = equals + + func do_get(): + return RdotComputed.computedGet(node) + +class Watcher: + var node: RdotNode + + func _init(notify: Callable): + var node = RdotNode.new() + node.wrapper = self + node.consumerMarkedDirty = notify + node.consumerIsAlwaysLive = true + node.consumerAllowSignalWrites = false + node.producerNode = [] + self.node = node + + ## signals: Array[RState | RComputed] + func _assertSignals(signals: Array): + for s in signals: + assert(s is State or s is Computed, "Watcher expects signals to be RState or RComputed") + + func watch(signals:=[]): + _assertSignals(signals) + + var graph = RdotGraph.getInstance() + + var node = self.node + node.dirty = false + var prev = graph.setActiveConsumer(node) + for s in signals: + graph.producerAccessed(s.node) + + graph.setActiveConsumer(prev) + + func unwatch(signals: Array): + _assertSignals(signals) + + var graph = RdotGraph.getInstance() + + var node = self.node + graph.assertConsumerNode(node) + + var indicesToShift = [] + for i in range(node.producerNode.size()): + if signals.has(node.producerNode[i].wrapper): + graph.producerRemoveLiveConsumerAtIndex(node.producerNode[i], node.producerIndexOfThis[i]) + indicesToShift.append(i) + + for idx in indicesToShift: + var lastIdx = node.producerNode.size() - 1 + node.producerNode[idx] = node.producerNode[lastIdx] + node.producerIndexOfThis[idx] = node.producerIndexOfThis[lastIdx] + + node.producerNode.pop_back() + node.producerIndexOfThis.pop_back() + node.nextProducerIndex -= 1 + + if idx < node.producerNode.size(): + var idxConsumer = node.producerNode[idx] + var producer = node.producerNode[idx] + + graph.assertProducerNode(producer) + + producer.liveConsumerIndexOfThis[idxConsumer] = idx + + ## Returns Array[RComputed] + func getPending() -> Array: + var node = self.node + + return node.producerNode.filter(func(n): return n.dirty).map(func(n): return n.wrapper) diff --git a/app/addons/rdot/array.gd b/app/addons/rdot/array.gd new file mode 100644 index 0000000..5638d60 --- /dev/null +++ b/app/addons/rdot/array.gd @@ -0,0 +1,13 @@ +class_name RdotArray + +static func do_set(array: Array, index: int, value): + if index >= array.size(): + array.resize(index + 1) + + array[index] = value + +static func do_get(array: Array, index: int): + if index >= array.size(): + return null + + return array[index] \ No newline at end of file diff --git a/app/addons/rdot/computed.gd b/app/addons/rdot/computed.gd new file mode 100644 index 0000000..3449042 --- /dev/null +++ b/app/addons/rdot/computed.gd @@ -0,0 +1,64 @@ +extends RdotNode +class_name RdotComputed + +enum State { + SET = 0, + UNSET = 1, + COMPUTING = 2, + ERRORED = 3 +} + +var value: Variant = null +var state: State = State.UNSET +var error = null +var computation := Callable() +var equal := func(this, a, b): return a == b + +static func computedGet(node: RdotComputed) -> Variant: + var graph := RdotGraph.getInstance() + + graph.producerUpdateValueVersion(node) + graph.producerAccessed(node) + + assert(node.state != State.ERRORED, "Error in computed.") + + return node.value + +static func createdComputed(computation: Callable): + var node = RdotComputed.new() + node.computation = computation + + var computed = func(): + return computedGet(node) + + return [computed, node] + +func producerMustRecompute(node: RdotNode) -> bool: + return node.state == State.UNSET or node.state == State.COMPUTING + +func _init(): + self.dirty = true + self.producerRecomputeValue = func(node: RdotNode): + assert(node.state != State.COMPUTING, "Detected cycle in computations.") + + var graph := RdotGraph.getInstance() + + var oldState = node.state + var oldValue = node.value + node.state = State.COMPUTING + + var prevConsumer = graph.consumerBeforeComputation(node) + var newValue = node.computation.call(node.wrapper) + var oldOk = oldState != State.UNSET&&oldState != State.ERRORED + var wasEqual = oldOk&&node.equal.call(node.wrapper, oldValue, newValue) + + graph.consumerAfterComputation(node, prevConsumer) + + if wasEqual: + node.value = oldValue + node.state = oldState + return + + node.value = newValue + node.state = State.SET + node.version += 1 \ No newline at end of file diff --git a/app/addons/rdot/graph.gd b/app/addons/rdot/graph.gd new file mode 100644 index 0000000..6fde0d0 --- /dev/null +++ b/app/addons/rdot/graph.gd @@ -0,0 +1,225 @@ +extends RefCounted +class_name RdotGraph + +static var instance: RdotGraph = null + +static func getInstance() -> RdotGraph: + if instance == null: + instance = RdotGraph.new() + return instance + +var activeConsumer: RdotNode = null +var inNotificationPhase := false + +var epoch := 1 + +var postSignalSetFn := Callable() +var watcherPending := false + +var watcher = R.Watcher.new(func(_arg): + if watcherPending: + return + + watcherPending=true + var endOfFrame=func(): + + watcherPending=false + for s in watcher.getPending(): + s.do_get() + + watcher.watch() + + endOfFrame.call_deferred() +) + +func setActiveConsumer(consumer: RdotNode) -> RdotNode: + var prev = activeConsumer + activeConsumer = consumer + return prev + +func getActiveConsumer() -> RdotNode: + return activeConsumer + +func isInNotificationPhase() -> bool: + return inNotificationPhase + +func producerAccessed(node: RdotNode): + assert(inNotificationPhase == false, "Signal read during notification phase") + + if activeConsumer == null: + return + + if activeConsumer.consumerOnSignalRead.is_null() == false: + activeConsumer.consumerOnSignalRead.call(node) + + var idx = activeConsumer.nextProducerIndex; + activeConsumer.nextProducerIndex += 1 + + assertConsumerNode(activeConsumer) + + if idx < activeConsumer.producerNode.size()&&activeConsumer.producerNode[idx] != node: + if consumerIsLive(activeConsumer): + var staleProducer = activeConsumer.producerNode[idx] + producerRemoveLiveConsumerAtIndex(staleProducer, activeConsumer.producerIndexOfThis[idx]) + + if RdotArray.do_get(activeConsumer.producerNode, idx) != node: + RdotArray.do_set(activeConsumer.producerNode, idx, node) + RdotArray.do_set(activeConsumer.producerIndexOfThis, idx, producerAddLiveConsumer(node, activeConsumer, idx) if consumerIsLive(activeConsumer) else 0) + + RdotArray.do_set(activeConsumer.producerLastReadVersion, idx, node.version) + +func producerIncrementEpoch(): + epoch += 1 + +func producerUpdateValueVersion(node: RdotNode): + if consumerIsLive(node)&&!node.dirty: + return + + if !node.dirty&&node.lastCleanEpoch == epoch: + return + + if !node.producerMustRecompute(node)&&!consumerPollProducersForChange(node): + node.dirty = false; + node.lastCleanEpoch = epoch + return + + if node.producerRecomputeValue.is_null() == false: + node.producerRecomputeValue.call(node) + + node.dirty = false + node.lastCleanEpoch = epoch + +func producerNotifyConsumers(node: RdotNode): + if node.liveConsumerNode == null: + return + + var prev = inNotificationPhase + inNotificationPhase = true + + for consumer in node.liveConsumerNode: + if !consumer.dirty: + consumerMarkDirty(consumer) + + inNotificationPhase = prev + +func producerUpdatesAllowed() -> bool: + return activeConsumer == null||activeConsumer.consumerAllowSignalWrites != false + +func consumerMarkDirty(node: RdotNode): + node.dirty = true + producerNotifyConsumers(node) + + if node.consumerMarkedDirty.is_null() == false: + node.consumerMarkedDirty.call(node) + +func consumerBeforeComputation(node: RdotNode) -> RdotNode: + if node: + node.nextProducerIndex = 0 + + return setActiveConsumer(node) + +func consumerAfterComputation(node: RdotNode, prevConsumer: RdotNode): + setActiveConsumer(prevConsumer) + + if node == null||node.producerNode == null||node.producerIndexOfThis == null||node.producerLastReadVersion == null: + return + + if consumerIsLive(node): + for i in range(node.nextProducerIndex, node.producerNode.size()): + producerRemoveLiveConsumerAtIndex(node.producerNode[i], node.producerIndexOfThis[i]) + + while node.producerNode.size() > node.nextProducerIndex: + node.producerNode.pop_back() + node.producerLastReadVersion.pop_back() + node.producerIndexOfThis.pop_back() + +func consumerPollProducersForChange(node: RdotNode) -> bool: + assertConsumerNode(node) + + for i in range(node.producerNode.size()): + var producer = node.producerNode[i] + var seenVersion = node.producerLastReadVersion[i] + + if seenVersion != producer.version: + return true + + producerUpdateValueVersion(producer) + + if seenVersion != producer.version: + return true + + return false + +func consumerDestroy(node: RdotNode): + assertConsumerNode(node) + + if consumerIsLive(node): + for i in range(node.producerNode.size()): + producerRemoveLiveConsumerAtIndex(node.producerNode[i], node.producerIndexOfThis[i]) + + node.producerNode.clear() + node.producerLastReadVersion.clear() + node.producerIndexOfThis.clear() + + if node.liveConsumerNode: + node.liveConsumerNode.clear() + node.liveConsumerIndexOfThis.clear() + +static func producerAddLiveConsumer(node: RdotNode, consumer: RdotNode, indexOfThis: int) -> int: + assertProducerNode(node) + assertConsumerNode(node) + + if node.liveConsumerNode.size() == 0: + if node.watched.is_null() == false: + node.watched.call(node.wrapper) + + for i in range(node.producerNode.size()): + node.producerIndexOfThis[i] = producerAddLiveConsumer(node.producerNode[i], node, i) + + node.liveConsumerIndexOfThis.push_back(indexOfThis) + node.liveConsumerNode.push_back(consumer) + + return node.liveConsumerNode.size() - 1 + +static func producerRemoveLiveConsumerAtIndex(node: RdotNode, idx: int): + assertProducerNode(node) + assertConsumerNode(node) + + assert(idx < node.liveConsumerNode.size(), "active consumer index %s is out of bounds of %s consumers)" % [idx, node.liveConsumerNode.size()]) + + if node.liveConsumerNode.size() == 1: + if node.unwatched.is_null() == false: + node.unwatched.call(node.wrapper) + + for i in range(node.producerNode.size()): + producerRemoveLiveConsumerAtIndex(node.producerNode[i], node.producerIndexOfThis[i]) + + var lastIdx = node.liveConsumerNode.size() - 1 + node.liveConsumerNode[idx] = node.liveConsumerNode[lastIdx] + node.liveConsumerIndexOfThis[idx] = node.liveConsumerIndexOfThis[lastIdx] + + node.liveConsumerNode.pop_back() + node.liveConsumerIndexOfThis.pop_back() + + if idx < node.liveConsumerNode.size(): + var idxProducer = node.liveConsumerIndexOfThis[idx] + var consumer = node.liveConsumerNode[idx] + assertConsumerNode(consumer) + consumer.producerIndexOfThis[idxProducer] = idx + +static func consumerIsLive(node: RdotNode) -> bool: + return node.consumerIsAlwaysLive||(node.liveConsumerNode != null&&node.liveConsumerNode.size() > 0) + +static func assertConsumerNode(node: RdotNode): + if node.producerNode == null: + node.producerNode = [] + if node.producerIndexOfThis == null: + node.producerIndexOfThis = [] + if node.producerLastReadVersion == null: + node.producerLastReadVersion = [] + +static func assertProducerNode(node: RdotNode): + if node.liveConsumerNode == null: + node.liveConsumerNode = [] + if node.liveConsumerIndexOfThis == null: + node.liveConsumerIndexOfThis = [] \ No newline at end of file diff --git a/app/addons/rdot/node.gd b/app/addons/rdot/node.gd new file mode 100644 index 0000000..f8b273e --- /dev/null +++ b/app/addons/rdot/node.gd @@ -0,0 +1,38 @@ +extends RefCounted +class_name RdotNode + +var version := 0 +var lastCleanEpoch := 0 +var dirty := false + +## Array[RdotNode] | null +var producerNode = null + +## Array[int] | null +var producerLastReadVersion = null + +## Array[int] | null +var producerIndexOfThis = null +var nextProducerIndex := 0 + +## Array[RdotNode] | null +var liveConsumerNode = null + +## Array[int] | null +var liveConsumerIndexOfThis = null +var consumerAllowSignalWrites := false +var consumerIsAlwaysLive := false + +var watched: Callable = Callable() +var unwatched: Callable = Callable() +var wrapper + +func producerMustRecompute(node: RdotNode) -> bool: + return false + +var producerRecomputeValue: Callable = Callable() +var consumerMarkedDirty: Callable = Callable() +var consumerOnSignalRead: Callable = Callable() + +# func _to_string(): +# return "RdotNode {\n" + ",\n\t".join(get_property_list().map(func(dict): return dict.name + ": " + str(get(dict.name)))) + "\n}" diff --git a/app/addons/rdot/state.gd b/app/addons/rdot/state.gd new file mode 100644 index 0000000..dcbdc20 --- /dev/null +++ b/app/addons/rdot/state.gd @@ -0,0 +1,50 @@ +extends RdotNode +class_name RdotState + +var equal: Callable = func(this, a, b): a == b +var value: Variant = null + +static func createSignal(initialValue: Variant): + var node = RdotState.new() + node.value = initialValue + + var getter = func(): + RdotGraph.getInstance().producerAccessed(node) + return node.value + + return [getter, node] + +static func setPostSignalSetFn(fn: Callable) -> Callable: + var graph := RdotGraph.getInstance() + var prev = graph.postSignalSetFn + graph.postSignalSetFn = fn + return prev + +static func signalGetFn(this: RdotState): + RdotGraph.getInstance().producerAccessed(this) + return this.value + +static func signalSetFn(node: RdotState, newValue: Variant): + var graph := RdotGraph.getInstance() + + assert(graph.producerUpdatesAllowed()) + + if !node.equal.call(node.wrapper, node.value, newValue): + node.value = newValue + signalValueChanged(node) + +static func signalUpdateFn(node: RdotState, updater: Callable): + var graph := RdotGraph.getInstance() + + assert(graph.producerUpdatesAllowed()) + + signalSetFn(node, updater.call(node.value)) + +static func signalValueChanged(node: RdotState): + var graph := RdotGraph.getInstance() + + node.version += 1 + graph.producerIncrementEpoch() + graph.producerNotifyConsumers(node) + if !graph.postSignalSetFn.is_null(): + graph.postSignalSetFn.call() diff --git a/app/addons/rdot/store.gd b/app/addons/rdot/store.gd new file mode 100644 index 0000000..d3ef73f --- /dev/null +++ b/app/addons/rdot/store.gd @@ -0,0 +1,37 @@ +extends Object +class_name RdotStore + +var _proxied_value = {} +var _property_list = [] + +func _init(initial_value: Dictionary={}): + _proxied_value = initial_value + + _property_list = _proxied_value.keys().map(func(key): + return { + "name": key, + "type": typeof(_proxied_value[key]) + } + ) + +func _get(property): + _access_property(property) + + if _proxied_value[property] is RdotStore: + return _proxied_value[property] + + return _proxied_value[property].value + +func _set(property, value): + _access_property(property) + + _proxied_value[property].value = value + + return true + +func _access_property(property): + if (_proxied_value[property] is R.State) == false: + _proxied_value[property] = R.state(_proxied_value[property]) + +func _get_property_list(): + return _property_list From e73db3ee47994dee7bb21c64baf18f93b5058d2e Mon Sep 17 00:00:00 2001 From: Nitwel Date: Tue, 9 Apr 2024 15:35:33 +0200 Subject: [PATCH 04/10] fix name collisions --- app/content/system/house/room/states/room_state.gd | 4 ++-- app/lib/utils/state_machine/state.gd | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/app/content/system/house/room/states/room_state.gd b/app/content/system/house/room/states/room_state.gd index 31e6877..567079b 100644 --- a/app/content/system/house/room/states/room_state.gd +++ b/app/content/system/house/room/states/room_state.gd @@ -1,5 +1,5 @@ -extends State -const Room = preload("res://content/system/house/room/room.gd") +extends MachineState +const Room = preload ("res://content/system/house/room/room.gd") var room: Room diff --git a/app/lib/utils/state_machine/state.gd b/app/lib/utils/state_machine/state.gd index b2a998f..2f874b2 100644 --- a/app/lib/utils/state_machine/state.gd +++ b/app/lib/utils/state_machine/state.gd @@ -1,6 +1,6 @@ extends Node ## Base Class for all states -class_name State +class_name MachineState var state_machine: StateMachine From b716f950bc772c947ae02984c516d6fe0917aaac Mon Sep 17 00:00:00 2001 From: Nitwel Date: Tue, 9 Apr 2024 17:11:24 +0200 Subject: [PATCH 05/10] update stores to be reactive --- .../hands/model/Hand_Glove_L.gltf.import | 2 + .../hands/model/Hand_Glove_R.gltf.import | 2 + .../hands/model/Hand_Glove_low_L.gltf.import | 2 + .../hands/model/Hand_Glove_low_R.gltf.import | 2 + .../hands/model/Hand_Nails_L.gltf.import | 2 + .../hands/model/Hand_Nails_R.gltf.import | 2 + .../hands/model/Hand_Nails_low_L.gltf.import | 2 + .../hands/model/Hand_Nails_low_R.gltf.import | 2 + .../hands/model/Hand_low_L.gltf.import | 2 + .../hands/model/Hand_low_R.gltf.import | 2 + .../hands/model/hand_l.gltf.import | 2 + .../hands/model/hand_r.gltf.import | 2 + app/addons/rdot/Rdot.gd | 28 ++++++------- app/addons/rdot/computed.gd | 6 +-- app/addons/rdot/state.gd | 12 +++--- app/addons/rdot/store.gd | 2 +- .../chat_bubble-flipped.glb.import | 2 +- .../models/chat_bubble/chat_bubble.glb.import | 2 +- app/assets/models/sky_dome/scene.gltf.import | 2 +- app/assets/models/sky_dome/scene_0.png | 3 ++ app/assets/models/sky_dome/scene_0.png.import | 37 +++++++++++++++++ app/assets/models/sky_dome/scene_4.png | 3 ++ app/assets/models/sky_dome/scene_4.png.import | 37 +++++++++++++++++ app/content/system/house/mini/miniature.gd | 4 +- app/content/ui/components/tabs/tabs.gd | 26 ++++++------ .../ui/components/tabs/tabs_content.gd | 17 ++++---- app/lib/stores/devices.gd | 5 ++- app/lib/stores/house.gd | 36 ++++++++-------- app/lib/stores/settings.gd | 32 +++++++-------- app/lib/stores/store.gd | 41 +++++++++---------- app/lib/utils/mesh/construct_room_mesh.gd | 1 - 31 files changed, 212 insertions(+), 108 deletions(-) create mode 100644 app/assets/models/sky_dome/scene_0.png create mode 100644 app/assets/models/sky_dome/scene_0.png.import create mode 100644 app/assets/models/sky_dome/scene_4.png create mode 100644 app/assets/models/sky_dome/scene_4.png.import diff --git a/app/addons/godot-xr-tools/hands/model/Hand_Glove_L.gltf.import b/app/addons/godot-xr-tools/hands/model/Hand_Glove_L.gltf.import index 1314ffb..ac26307 100644 --- a/app/addons/godot-xr-tools/hands/model/Hand_Glove_L.gltf.import +++ b/app/addons/godot-xr-tools/hands/model/Hand_Glove_L.gltf.import @@ -22,6 +22,7 @@ meshes/generate_lods=true meshes/create_shadow_meshes=true meshes/light_baking=1 meshes/lightmap_texel_size=0.2 +meshes/force_disable_compression=false skins/use_named_skins=true animation/import=true animation/fps=30 @@ -29,4 +30,5 @@ animation/trimming=false animation/remove_immutable_tracks=true import_script/path="" _subresources={} +gltf/naming_version=0 gltf/embedded_image_handling=1 diff --git a/app/addons/godot-xr-tools/hands/model/Hand_Glove_R.gltf.import b/app/addons/godot-xr-tools/hands/model/Hand_Glove_R.gltf.import index 8c12245..6bb5437 100644 --- a/app/addons/godot-xr-tools/hands/model/Hand_Glove_R.gltf.import +++ b/app/addons/godot-xr-tools/hands/model/Hand_Glove_R.gltf.import @@ -22,6 +22,7 @@ meshes/generate_lods=true meshes/create_shadow_meshes=true meshes/light_baking=1 meshes/lightmap_texel_size=0.2 +meshes/force_disable_compression=false skins/use_named_skins=true animation/import=true animation/fps=30 @@ -29,4 +30,5 @@ animation/trimming=false animation/remove_immutable_tracks=true import_script/path="" _subresources={} +gltf/naming_version=0 gltf/embedded_image_handling=1 diff --git a/app/addons/godot-xr-tools/hands/model/Hand_Glove_low_L.gltf.import b/app/addons/godot-xr-tools/hands/model/Hand_Glove_low_L.gltf.import index 6fb44fe..1daeb3d 100644 --- a/app/addons/godot-xr-tools/hands/model/Hand_Glove_low_L.gltf.import +++ b/app/addons/godot-xr-tools/hands/model/Hand_Glove_low_L.gltf.import @@ -22,6 +22,7 @@ meshes/generate_lods=true meshes/create_shadow_meshes=true meshes/light_baking=1 meshes/lightmap_texel_size=0.2 +meshes/force_disable_compression=false skins/use_named_skins=true animation/import=true animation/fps=30 @@ -29,4 +30,5 @@ animation/trimming=false animation/remove_immutable_tracks=true import_script/path="" _subresources={} +gltf/naming_version=0 gltf/embedded_image_handling=1 diff --git a/app/addons/godot-xr-tools/hands/model/Hand_Glove_low_R.gltf.import b/app/addons/godot-xr-tools/hands/model/Hand_Glove_low_R.gltf.import index 31c5355..61667fe 100644 --- a/app/addons/godot-xr-tools/hands/model/Hand_Glove_low_R.gltf.import +++ b/app/addons/godot-xr-tools/hands/model/Hand_Glove_low_R.gltf.import @@ -22,6 +22,7 @@ meshes/generate_lods=true meshes/create_shadow_meshes=true meshes/light_baking=1 meshes/lightmap_texel_size=0.2 +meshes/force_disable_compression=false skins/use_named_skins=true animation/import=true animation/fps=30 @@ -29,4 +30,5 @@ animation/trimming=false animation/remove_immutable_tracks=true import_script/path="" _subresources={} +gltf/naming_version=0 gltf/embedded_image_handling=1 diff --git a/app/addons/godot-xr-tools/hands/model/Hand_Nails_L.gltf.import b/app/addons/godot-xr-tools/hands/model/Hand_Nails_L.gltf.import index fb4f1ce..b845079 100644 --- a/app/addons/godot-xr-tools/hands/model/Hand_Nails_L.gltf.import +++ b/app/addons/godot-xr-tools/hands/model/Hand_Nails_L.gltf.import @@ -22,6 +22,7 @@ meshes/generate_lods=true meshes/create_shadow_meshes=true meshes/light_baking=1 meshes/lightmap_texel_size=0.2 +meshes/force_disable_compression=false skins/use_named_skins=true animation/import=true animation/fps=30 @@ -29,4 +30,5 @@ animation/trimming=false animation/remove_immutable_tracks=true import_script/path="" _subresources={} +gltf/naming_version=0 gltf/embedded_image_handling=1 diff --git a/app/addons/godot-xr-tools/hands/model/Hand_Nails_R.gltf.import b/app/addons/godot-xr-tools/hands/model/Hand_Nails_R.gltf.import index d198397..b30506a 100644 --- a/app/addons/godot-xr-tools/hands/model/Hand_Nails_R.gltf.import +++ b/app/addons/godot-xr-tools/hands/model/Hand_Nails_R.gltf.import @@ -22,6 +22,7 @@ meshes/generate_lods=true meshes/create_shadow_meshes=true meshes/light_baking=1 meshes/lightmap_texel_size=0.2 +meshes/force_disable_compression=false skins/use_named_skins=true animation/import=true animation/fps=30 @@ -29,4 +30,5 @@ animation/trimming=false animation/remove_immutable_tracks=true import_script/path="" _subresources={} +gltf/naming_version=0 gltf/embedded_image_handling=1 diff --git a/app/addons/godot-xr-tools/hands/model/Hand_Nails_low_L.gltf.import b/app/addons/godot-xr-tools/hands/model/Hand_Nails_low_L.gltf.import index 40d4e92..ddd426c 100644 --- a/app/addons/godot-xr-tools/hands/model/Hand_Nails_low_L.gltf.import +++ b/app/addons/godot-xr-tools/hands/model/Hand_Nails_low_L.gltf.import @@ -22,6 +22,7 @@ meshes/generate_lods=true meshes/create_shadow_meshes=true meshes/light_baking=1 meshes/lightmap_texel_size=0.2 +meshes/force_disable_compression=false skins/use_named_skins=true animation/import=true animation/fps=30 @@ -29,4 +30,5 @@ animation/trimming=false animation/remove_immutable_tracks=true import_script/path="" _subresources={} +gltf/naming_version=0 gltf/embedded_image_handling=1 diff --git a/app/addons/godot-xr-tools/hands/model/Hand_Nails_low_R.gltf.import b/app/addons/godot-xr-tools/hands/model/Hand_Nails_low_R.gltf.import index 53fea66..561edee 100644 --- a/app/addons/godot-xr-tools/hands/model/Hand_Nails_low_R.gltf.import +++ b/app/addons/godot-xr-tools/hands/model/Hand_Nails_low_R.gltf.import @@ -22,6 +22,7 @@ meshes/generate_lods=true meshes/create_shadow_meshes=true meshes/light_baking=1 meshes/lightmap_texel_size=0.2 +meshes/force_disable_compression=false skins/use_named_skins=true animation/import=true animation/fps=30 @@ -29,4 +30,5 @@ animation/trimming=false animation/remove_immutable_tracks=true import_script/path="" _subresources={} +gltf/naming_version=0 gltf/embedded_image_handling=1 diff --git a/app/addons/godot-xr-tools/hands/model/Hand_low_L.gltf.import b/app/addons/godot-xr-tools/hands/model/Hand_low_L.gltf.import index 44b7650..db27d98 100644 --- a/app/addons/godot-xr-tools/hands/model/Hand_low_L.gltf.import +++ b/app/addons/godot-xr-tools/hands/model/Hand_low_L.gltf.import @@ -22,6 +22,7 @@ meshes/generate_lods=true meshes/create_shadow_meshes=true meshes/light_baking=1 meshes/lightmap_texel_size=0.2 +meshes/force_disable_compression=false skins/use_named_skins=true animation/import=true animation/fps=30 @@ -29,4 +30,5 @@ animation/trimming=false animation/remove_immutable_tracks=true import_script/path="" _subresources={} +gltf/naming_version=0 gltf/embedded_image_handling=1 diff --git a/app/addons/godot-xr-tools/hands/model/Hand_low_R.gltf.import b/app/addons/godot-xr-tools/hands/model/Hand_low_R.gltf.import index dcf37b5..a35d186 100644 --- a/app/addons/godot-xr-tools/hands/model/Hand_low_R.gltf.import +++ b/app/addons/godot-xr-tools/hands/model/Hand_low_R.gltf.import @@ -22,6 +22,7 @@ meshes/generate_lods=true meshes/create_shadow_meshes=true meshes/light_baking=1 meshes/lightmap_texel_size=0.2 +meshes/force_disable_compression=false skins/use_named_skins=true animation/import=true animation/fps=30 @@ -29,4 +30,5 @@ animation/trimming=false animation/remove_immutable_tracks=true import_script/path="" _subresources={} +gltf/naming_version=0 gltf/embedded_image_handling=1 diff --git a/app/addons/godot-xr-tools/hands/model/hand_l.gltf.import b/app/addons/godot-xr-tools/hands/model/hand_l.gltf.import index 326d084..90a575c 100644 --- a/app/addons/godot-xr-tools/hands/model/hand_l.gltf.import +++ b/app/addons/godot-xr-tools/hands/model/hand_l.gltf.import @@ -22,6 +22,7 @@ meshes/generate_lods=true meshes/create_shadow_meshes=true meshes/light_baking=1 meshes/lightmap_texel_size=0.2 +meshes/force_disable_compression=false skins/use_named_skins=true animation/import=true animation/fps=30 @@ -29,4 +30,5 @@ animation/trimming=false animation/remove_immutable_tracks=true import_script/path="" _subresources={} +gltf/naming_version=0 gltf/embedded_image_handling=1 diff --git a/app/addons/godot-xr-tools/hands/model/hand_r.gltf.import b/app/addons/godot-xr-tools/hands/model/hand_r.gltf.import index 1f91a8d..32df37f 100644 --- a/app/addons/godot-xr-tools/hands/model/hand_r.gltf.import +++ b/app/addons/godot-xr-tools/hands/model/hand_r.gltf.import @@ -22,6 +22,7 @@ meshes/generate_lods=true meshes/create_shadow_meshes=true meshes/light_baking=1 meshes/lightmap_texel_size=0.2 +meshes/force_disable_compression=false skins/use_named_skins=true animation/import=true animation/fps=30 @@ -29,4 +30,5 @@ animation/trimming=false animation/remove_immutable_tracks=true import_script/path="" _subresources={} +gltf/naming_version=0 gltf/embedded_image_handling=1 diff --git a/app/addons/rdot/Rdot.gd b/app/addons/rdot/Rdot.gd index 7b52ca3..e0e2d33 100644 --- a/app/addons/rdot/Rdot.gd +++ b/app/addons/rdot/Rdot.gd @@ -4,13 +4,13 @@ static func state(value: Variant, options: Dictionary={}): if value is Dictionary: return store(value) - return State.new(value, options) + return RdotState.new(value, options) static func store(value: Dictionary): return RdotStore.new(value) static func computed(computation: Callable, options: Dictionary={}): - return Computed.new(computation, options) + return RdotComputed.new(computation, options) ## DIY overloading of ## bind(target, prop, value) @@ -20,7 +20,7 @@ static func bind(target, prop, value, arg1=null, arg2=null): if value is RdotStore: return _bind_store(target, prop, value, arg1, arg2) - if value is State or value is Computed: + if value is RdotState or value is RdotComputed: return _bind_state(target, prop, value, arg1) assert(false, "Invalid arguments to bind, value must be a R.State or a RdotStore") @@ -77,8 +77,8 @@ static func effect(callback: Callable): graph.watcher.unwatch([c]) -class State: - var node: RdotState +class RdotState: + var node: RdotStateInternal var value = null: get: return do_get() @@ -86,7 +86,7 @@ class State: do_set(value) func _init(value: Variant, options: Dictionary={}): - var ref = RdotState.createSignal(value) + var ref = RdotStateInternal.createSignal(value) var node = ref[1] self.node = node node.wrapper = self @@ -98,7 +98,7 @@ class State: node.equals = equals func do_get(): - return RdotState.signalGetFn.call(self.node) + return RdotStateInternal.signalGetFn.call(self.node) func do_set(value: Variant): var graph = RdotGraph.getInstance() @@ -107,10 +107,10 @@ class State: var ref = self.node - RdotState.signalSetFn.call(ref, value) + RdotStateInternal.signalSetFn.call(ref, value) -class Computed: - var node: RdotComputed +class RdotComputed: + var node: RdotComputedInternal var value = null: get: return do_get() @@ -118,7 +118,7 @@ class Computed: pass func _init(computation: Callable, options: Dictionary={}): - var ref = RdotComputed.createdComputed(computation) + var ref = RdotComputedInternal.createdComputed(computation) var node = ref[1] node.consumerAllowSignalWrites = true self.node = node @@ -131,7 +131,7 @@ class Computed: node.equals = equals func do_get(): - return RdotComputed.computedGet(node) + return RdotComputedInternal.computedGet(node) class Watcher: var node: RdotNode @@ -145,10 +145,10 @@ class Watcher: node.producerNode = [] self.node = node - ## signals: Array[RState | RComputed] + ## signals: Array[RdotState | RComputed] func _assertSignals(signals: Array): for s in signals: - assert(s is State or s is Computed, "Watcher expects signals to be RState or RComputed") + assert(s is RdotState or s is RdotComputed, "Watcher expects signals to be RdotState or RdotComputed") func watch(signals:=[]): _assertSignals(signals) diff --git a/app/addons/rdot/computed.gd b/app/addons/rdot/computed.gd index 3449042..bb72b41 100644 --- a/app/addons/rdot/computed.gd +++ b/app/addons/rdot/computed.gd @@ -1,5 +1,5 @@ extends RdotNode -class_name RdotComputed +class_name RdotComputedInternal enum State { SET = 0, @@ -14,7 +14,7 @@ var error = null var computation := Callable() var equal := func(this, a, b): return a == b -static func computedGet(node: RdotComputed) -> Variant: +static func computedGet(node: RdotComputedInternal) -> Variant: var graph := RdotGraph.getInstance() graph.producerUpdateValueVersion(node) @@ -25,7 +25,7 @@ static func computedGet(node: RdotComputed) -> Variant: return node.value static func createdComputed(computation: Callable): - var node = RdotComputed.new() + var node = RdotComputedInternal.new() node.computation = computation var computed = func(): diff --git a/app/addons/rdot/state.gd b/app/addons/rdot/state.gd index dcbdc20..35a6bc0 100644 --- a/app/addons/rdot/state.gd +++ b/app/addons/rdot/state.gd @@ -1,11 +1,11 @@ extends RdotNode -class_name RdotState +class_name RdotStateInternal var equal: Callable = func(this, a, b): a == b var value: Variant = null static func createSignal(initialValue: Variant): - var node = RdotState.new() + var node = RdotStateInternal.new() node.value = initialValue var getter = func(): @@ -20,11 +20,11 @@ static func setPostSignalSetFn(fn: Callable) -> Callable: graph.postSignalSetFn = fn return prev -static func signalGetFn(this: RdotState): +static func signalGetFn(this: RdotStateInternal): RdotGraph.getInstance().producerAccessed(this) return this.value -static func signalSetFn(node: RdotState, newValue: Variant): +static func signalSetFn(node: RdotStateInternal, newValue: Variant): var graph := RdotGraph.getInstance() assert(graph.producerUpdatesAllowed()) @@ -33,14 +33,14 @@ static func signalSetFn(node: RdotState, newValue: Variant): node.value = newValue signalValueChanged(node) -static func signalUpdateFn(node: RdotState, updater: Callable): +static func signalUpdateFn(node: RdotStateInternal, updater: Callable): var graph := RdotGraph.getInstance() assert(graph.producerUpdatesAllowed()) signalSetFn(node, updater.call(node.value)) -static func signalValueChanged(node: RdotState): +static func signalValueChanged(node: RdotStateInternal): var graph := RdotGraph.getInstance() node.version += 1 diff --git a/app/addons/rdot/store.gd b/app/addons/rdot/store.gd index d3ef73f..abee4d1 100644 --- a/app/addons/rdot/store.gd +++ b/app/addons/rdot/store.gd @@ -30,7 +30,7 @@ func _set(property, value): return true func _access_property(property): - if (_proxied_value[property] is R.State) == false: + if (_proxied_value[property] is R.RdotState) == false: _proxied_value[property] = R.state(_proxied_value[property]) func _get_property_list(): diff --git a/app/assets/models/chat_bubble/chat_bubble-flipped.glb.import b/app/assets/models/chat_bubble/chat_bubble-flipped.glb.import index 3161c82..5d18a94 100644 --- a/app/assets/models/chat_bubble/chat_bubble-flipped.glb.import +++ b/app/assets/models/chat_bubble/chat_bubble-flipped.glb.import @@ -30,5 +30,5 @@ animation/trimming=false animation/remove_immutable_tracks=true import_script/path="" _subresources={} -gltf/naming_version=1 +gltf/naming_version=0 gltf/embedded_image_handling=1 diff --git a/app/assets/models/chat_bubble/chat_bubble.glb.import b/app/assets/models/chat_bubble/chat_bubble.glb.import index f0166c8..fa93cd6 100644 --- a/app/assets/models/chat_bubble/chat_bubble.glb.import +++ b/app/assets/models/chat_bubble/chat_bubble.glb.import @@ -30,5 +30,5 @@ animation/trimming=false animation/remove_immutable_tracks=true import_script/path="" _subresources={} -gltf/naming_version=1 +gltf/naming_version=0 gltf/embedded_image_handling=1 diff --git a/app/assets/models/sky_dome/scene.gltf.import b/app/assets/models/sky_dome/scene.gltf.import index 6efbee2..1f37b52 100644 --- a/app/assets/models/sky_dome/scene.gltf.import +++ b/app/assets/models/sky_dome/scene.gltf.import @@ -30,5 +30,5 @@ animation/trimming=false animation/remove_immutable_tracks=true import_script/path="" _subresources={} -gltf/naming_version=1 +gltf/naming_version=0 gltf/embedded_image_handling=1 diff --git a/app/assets/models/sky_dome/scene_0.png b/app/assets/models/sky_dome/scene_0.png new file mode 100644 index 0000000..269272e --- /dev/null +++ b/app/assets/models/sky_dome/scene_0.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:2941c9ce2676249f899aea64a13012d3b2f52dcf239d5f0c09570f14a4433348 +size 7954301 diff --git a/app/assets/models/sky_dome/scene_0.png.import b/app/assets/models/sky_dome/scene_0.png.import new file mode 100644 index 0000000..322fac0 --- /dev/null +++ b/app/assets/models/sky_dome/scene_0.png.import @@ -0,0 +1,37 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://d0vi854404eve" +path.s3tc="res://.godot/imported/scene_0.png-9a0770c34bd6836b2bfe1d70dcace53b.s3tc.ctex" +path.etc2="res://.godot/imported/scene_0.png-9a0770c34bd6836b2bfe1d70dcace53b.etc2.ctex" +metadata={ +"imported_formats": ["s3tc_bptc", "etc2_astc"], +"vram_texture": true +} +generator_parameters={} + +[deps] + +source_file="res://assets/models/sky_dome/scene_0.png" +dest_files=["res://.godot/imported/scene_0.png-9a0770c34bd6836b2bfe1d70dcace53b.s3tc.ctex", "res://.godot/imported/scene_0.png-9a0770c34bd6836b2bfe1d70dcace53b.etc2.ctex"] + +[params] + +compress/mode=2 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=true +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=0 diff --git a/app/assets/models/sky_dome/scene_4.png b/app/assets/models/sky_dome/scene_4.png new file mode 100644 index 0000000..882790f --- /dev/null +++ b/app/assets/models/sky_dome/scene_4.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:e93ccbdefa9cb54244f602dd3361a296a51c1cf1b4ca69344408b3f81853c6d7 +size 7587197 diff --git a/app/assets/models/sky_dome/scene_4.png.import b/app/assets/models/sky_dome/scene_4.png.import new file mode 100644 index 0000000..39d249f --- /dev/null +++ b/app/assets/models/sky_dome/scene_4.png.import @@ -0,0 +1,37 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://ds78ylaicfb3u" +path.s3tc="res://.godot/imported/scene_4.png-a9e7d42c59bc553f60827e5915c54b69.s3tc.ctex" +path.etc2="res://.godot/imported/scene_4.png-a9e7d42c59bc553f60827e5915c54b69.etc2.ctex" +metadata={ +"imported_formats": ["s3tc_bptc", "etc2_astc"], +"vram_texture": true +} +generator_parameters={} + +[deps] + +source_file="res://assets/models/sky_dome/scene_4.png" +dest_files=["res://.godot/imported/scene_4.png-a9e7d42c59bc553f60827e5915c54b69.s3tc.ctex", "res://.godot/imported/scene_4.png-a9e7d42c59bc553f60827e5915c54b69.etc2.ctex"] + +[params] + +compress/mode=2 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=true +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=0 diff --git a/app/content/system/house/mini/miniature.gd b/app/content/system/house/mini/miniature.gd index 66004c9..74413f7 100644 --- a/app/content/system/house/mini/miniature.gd +++ b/app/content/system/house/mini/miniature.gd @@ -60,7 +60,7 @@ const SensorEntity = preload ("res://content/entities/sensor/sensor.gd") var active: bool = false -func update_data(delta: float) -> void: +func update_data(_delta: float) -> void: var data_list = [] for room in House.body.get_rooms(0): @@ -80,7 +80,5 @@ func update_data(delta: float) -> void: return data ) - print(data_list) - wall_material.set_shader_parameter("data", data_list) wall_material.set_shader_parameter("data_size", data_list.size()) diff --git a/app/content/ui/components/tabs/tabs.gd b/app/content/ui/components/tabs/tabs.gd index c31150d..21c6c95 100644 --- a/app/content/ui/components/tabs/tabs.gd +++ b/app/content/ui/components/tabs/tabs.gd @@ -3,29 +3,29 @@ class_name Tabs3D signal on_select(selected: int) -var selected: Node3D: - set(value): - if selected == value: - return +var selected = R.state(null) - if selected != null: - selected.active = false - - selected = value - selected.active = true - on_select.emit(selected.get_index()) @export var initial_selected: Node3D func _ready(): - if initial_selected != null: - selected = initial_selected + if initial_selected: + selected.value = initial_selected + + R.effect(func(_arg): + on_select.emit(selected.value) + ) for option in get_children(): if option is Button3D == false: continue option.on_button_down.connect(func(): - selected=option + selected.value=option + ) + + R.effect(func(_arg): + option.active=option == selected.value + option.disabled=option == selected.value ) option.toggleable = true diff --git a/app/content/ui/components/tabs/tabs_content.gd b/app/content/ui/components/tabs/tabs_content.gd index 73d3052..181d298 100644 --- a/app/content/ui/components/tabs/tabs_content.gd +++ b/app/content/ui/components/tabs/tabs_content.gd @@ -8,15 +8,14 @@ var children: Array = [] func _ready(): children = get_children() - for child in children: + for i in range(children.size()): + var child = children[i] child.visible = true - if tabs.selected != null && tabs.selected.get_index() == child.get_index(): - continue remove_child(child) - tabs.on_select.connect(func(index): - for child in get_children(): - remove_child(child) - - add_child(children[index]) - ) + R.effect(func(_arg): + if tabs.selected.value.get_index() == i: + add_child(child) + else: + remove_child(child) + ) diff --git a/app/lib/stores/devices.gd b/app/lib/stores/devices.gd index df2a8e2..c3bf2ab 100644 --- a/app/lib/stores/devices.gd +++ b/app/lib/stores/devices.gd @@ -1,5 +1,8 @@ extends StoreClass -const StoreClass = preload("./store.gd") +const StoreClass = preload ("./store.gd") + +func _init(): + self.state = R.state({}) func clear(): pass \ No newline at end of file diff --git a/app/lib/stores/house.gd b/app/lib/stores/house.gd index d135c6c..57de618 100644 --- a/app/lib/stores/house.gd +++ b/app/lib/stores/house.gd @@ -3,29 +3,31 @@ extends StoreClass const StoreClass = preload ("./store.gd") -## Type Room -## name: String -## corners: Vec2[] -## height: float -var rooms = [] -## Type Entity -## id: String -## position: Vec3 -## rotation: Vec3 -## room: String -var entities = [] -var align_position1: Vector3 -var align_position2: Vector3 - func _init(): _save_path = "user://house.json" + self.state = R.store({ + ## Type Room + ## name: String + ## corners: Vec2[] + ## height: float + "rooms": [], + ## Type Entity + ## id: String + ## position: Vec3 + ## rotation: Vec3 + ## room: String + "entities": [], + "align_position1": Vector3(), + "align_position2": Vector3() + }) + func clear(): - rooms = [] - entities = [] + self.state.rooms = [] + self.state.entities = [] func get_room(name): - for room in rooms: + for room in self.state.rooms: if room.name == name: return room return null \ No newline at end of file diff --git a/app/lib/stores/settings.gd b/app/lib/stores/settings.gd index 84d50fd..f24c16b 100644 --- a/app/lib/stores/settings.gd +++ b/app/lib/stores/settings.gd @@ -3,23 +3,23 @@ extends StoreClass const StoreClass = preload ("./store.gd") -## The adapter to use for connecting with a backend -var type: String = "HASS_WS" -var url: String = "" -var token: String = "" - -## If the voice assistant should be enabled -var voice_assistant: bool = false - -## If the onboarding process has been completed -var onboarding_complete: bool = false - func _init(): _save_path = "user://settings.json" + self.state = R.store({ + ## The adapter to use for connecting with a backend + "type": "HASS_WS", + "url": "", + "token": "", + ## If the voice assistant should be enabled + "voice_assistant": false, + ## If the onboarding process has been completed + "onboarding_complete": false + }) + func clear(): - type = "HASS_WS" - url = "" - token = "" - voice_assistant = false - onboarding_complete = false \ No newline at end of file + self.state.type = "HASS_WS" + self.state.url = "" + self.state.token = "" + self.state.voice_assistant = false + self.state.onboarding_complete = false \ No newline at end of file diff --git a/app/lib/stores/store.gd b/app/lib/stores/store.gd index fb058b3..e00bcea 100644 --- a/app/lib/stores/store.gd +++ b/app/lib/stores/store.gd @@ -9,6 +9,7 @@ signal on_loaded ## Signal emitted when the data is saved. signal on_saved +var state: RdotStore var _loaded = false var _save_path = null @@ -20,44 +21,42 @@ func is_loaded(): func clear(): pass -func create_dict(): - var data: Dictionary = {} +func sanitizeState(dict=state): + var data = {} for prop_info in get_property_list(): - if prop_info.name.begins_with("_")||prop_info.hint_string != "": + var key = prop_info.name + + if key.begins_with("_")||(prop_info.has("hint_string")&&prop_info.hint_string != ""): continue - var prop = get(prop_info.name) - - if prop is Store: - data[prop_info.name] = prop.create_dict() + if dict[key] is Dictionary: + data[key] = sanitizeState(dict[key]) else: - data[prop_info.name] = VariantSerializer.stringify_value(prop) + data[key] = VariantSerializer.stringify_value(dict[key]) return data -func use_dict(dict: Dictionary): +func use_dict(dict: Dictionary, target=state): for prop_info in get_property_list(): - if prop_info.name.begins_with("_")||prop_info.hint_string != "": + var key = prop_info.name + + if key.begins_with("_")||(prop_info.has("hint_string")&&prop_info.hint_string != ""): + continue + + if dict.has(key) == false: continue - var prop = get(prop_info.name) - - if dict.has(prop_info.name) == false: - continue - - var prop_value = dict[prop_info.name] - - if prop is Store: - prop.use_dict(prop_value) + if target[key] is Dictionary: + use_dict(dict[key], target[key]) else: - set(prop_info.name, prop_value) + target[key] = dict[key] func save_local(path=_save_path): if path == null: return false - var data = create_dict() + var data = sanitizeState() var save_file = FileAccess.open(path, FileAccess.WRITE) diff --git a/app/lib/utils/mesh/construct_room_mesh.gd b/app/lib/utils/mesh/construct_room_mesh.gd index b0045ce..92da23f 100644 --- a/app/lib/utils/mesh/construct_room_mesh.gd +++ b/app/lib/utils/mesh/construct_room_mesh.gd @@ -79,7 +79,6 @@ static func generate_wall_mesh_grid(corners, height, grid: Vector2=Vector2(0.1, if y == steps.y - 1: close_distance.y = fmod(height, grid.y) / grid.y - print(close_distance.y) for x in range(0, steps.x): var point = corner + forward_dir * x + Vector3.UP * grid.y * y From 2cb35ef02bb213876f0030287c5aeca645c58077 Mon Sep 17 00:00:00 2001 From: Nitwel Date: Tue, 9 Apr 2024 17:46:59 +0200 Subject: [PATCH 06/10] fix store references --- app/addons/rdot/Rdot.gd | 2 +- app/content/main.gd | 20 ++++++++----- app/content/system/house/align_reference.gd | 8 ++--- app/content/system/house/house.gd | 18 ++++++------ app/content/system/house/mini/miniature.gd | 4 +-- app/content/ui/menu/room/views/rooms.gd | 2 +- app/content/ui/menu/settings/settings_menu.gd | 29 ++++++++++--------- app/content/ui/onboarding/onboarding.gd | 4 +-- app/lib/globals/home_api.gd | 3 +- app/lib/stores/settings.gd | 2 +- app/lib/stores/store.gd | 6 ++-- 11 files changed, 53 insertions(+), 45 deletions(-) diff --git a/app/addons/rdot/Rdot.gd b/app/addons/rdot/Rdot.gd index e0e2d33..6428a86 100644 --- a/app/addons/rdot/Rdot.gd +++ b/app/addons/rdot/Rdot.gd @@ -23,7 +23,7 @@ static func bind(target, prop, value, arg1=null, arg2=null): if value is RdotState or value is RdotComputed: return _bind_state(target, prop, value, arg1) - assert(false, "Invalid arguments to bind, value must be a R.State or a RdotStore") + assert(false, "Invalid arguments to bind, value must be a RdotState, a RdotComputed or a RdotStore") static func _bind_store(target, prop, store: RdotStore, key, watch_signal=null): store._access_property(key) diff --git a/app/content/main.gd b/app/content/main.gd index dbf478b..75a43b2 100644 --- a/app/content/main.gd +++ b/app/content/main.gd @@ -22,7 +22,7 @@ func _ready(): else: RenderingServer.set_debug_generate_wireframes(true) - update_voice_assistant() + create_voice_assistant() controller_left.button_pressed.connect(func(name): _emit_action(name, true, false) @@ -65,16 +65,20 @@ func _ready(): remove_child(keyboard) ) -func update_voice_assistant(): +func create_voice_assistant(): if Store.settings.is_loaded() == false: await Store.settings.on_loaded - if Store.settings.voice_assistant&&voice_assistant == null: - voice_assistant = VoiceAssistant.instantiate() - add_child(voice_assistant) - elif !Store.settings.voice_assistant&&voice_assistant != null: - remove_child(voice_assistant) - voice_assistant.queue_free() + var settings_store = Store.settings.state + + R.effect(func(_arg): + if settings_store.voice_assistant == true&&voice_assistant == null: + voice_assistant=VoiceAssistant.instantiate() + add_child(voice_assistant) + elif settings_store.voice_assistant == false&&voice_assistant != null: + remove_child(voice_assistant) + voice_assistant.queue_free() + ) func toggle_menu(): if menu.show_menu == false: diff --git a/app/content/system/house/align_reference.gd b/app/content/system/house/align_reference.gd index 0118f58..c4e1242 100644 --- a/app/content/system/house/align_reference.gd +++ b/app/content/system/house/align_reference.gd @@ -48,8 +48,8 @@ func get_new_transform(): return marker.global_transform func update_align_reference(): - corner1.global_position = Store.house.align_position1 - corner2.global_position = Store.house.align_position2 + corner1.global_position = Store.house.state.align_position1 + corner2.global_position = Store.house.state.align_position2 corner2.look_at(corner1.global_position, Vector3.UP) corner2.rotate(Vector3.UP, deg_to_rad( - 90)) @@ -57,5 +57,5 @@ func update_align_reference(): edge.align_to_corners(corner1.global_position, corner2.global_position) func update_store(): - Store.house.align_position1 = corner1.global_position - Store.house.align_position2 = corner2.global_position \ No newline at end of file + Store.house.state.align_position1 = corner1.global_position + Store.house.state.align_position2 = corner2.global_position \ No newline at end of file diff --git a/app/content/system/house/house.gd b/app/content/system/house/house.gd index 9d8392b..c5517fa 100644 --- a/app/content/system/house/house.gd +++ b/app/content/system/house/house.gd @@ -23,18 +23,18 @@ func update_house(): align_reference.update_align_reference() - for index in range(Store.house.rooms.size() - 1, -1, -1): - var new_room = Store.house.rooms[index] + for index in range(Store.house.state.rooms.size() - 1, -1, -1): + var new_room = Store.house.state.rooms[index] if new_room.corners.size() == 0: - Store.house.rooms.remove_at(index) + Store.house.state.rooms.remove_at(index) Store.house.save_local() continue create_room(new_room.name, 0) - for entity_index in range(Store.house.entities.size()): - var entity = Store.house.entities[entity_index] + for entity_index in range(Store.house.state.entities.size()): + var entity = Store.house.state.entities[entity_index] var entity_instance = create_entity_in(entity.id, entity.room) @@ -48,7 +48,7 @@ func create_room(room_name: String, level: int) -> RoomType: var existing_room = Store.house.get_room(room_name) if existing_room == null: - Store.house.rooms.append({ + Store.house.state.rooms.append({ "name": room_name, "height": 2.0, "corners": [], @@ -98,7 +98,7 @@ func delete_room(room_name): var store_room = Store.house.get_room(room_name) if store_room != null: - Store.house.rooms.erase(store_room) + Store.house.state.rooms.erase(store_room) Store.house.save_local() @@ -229,7 +229,7 @@ func save_reference(): Store.house.save_local() func save_all_entities(): - Store.house.entities.clear() + Store.house.state.entities.clear() for room in get_rooms(0): for entity in room.get_node("Entities").get_children(): @@ -240,6 +240,6 @@ func save_all_entities(): "room": String(room.name) } - Store.house.entities.append(entity_data) + Store.house.state.entities.append(entity_data) Store.house.save_local() diff --git a/app/content/system/house/mini/miniature.gd b/app/content/system/house/mini/miniature.gd index 74413f7..7cd4b08 100644 --- a/app/content/system/house/mini/miniature.gd +++ b/app/content/system/house/mini/miniature.gd @@ -22,10 +22,10 @@ func _ready(): if Store.house.is_loaded() == false: await Store.house.on_loaded - if Store.house.rooms.size() == 0: + if Store.house.state.rooms.size() == 0: return - var room = Store.house.rooms[0] + var room = Store.house.state.rooms[0] var corners = room.corners var height = room.height diff --git a/app/content/ui/menu/room/views/rooms.gd b/app/content/ui/menu/room/views/rooms.gd index 298e13c..967583f 100644 --- a/app/content/ui/menu/room/views/rooms.gd +++ b/app/content/ui/menu/room/views/rooms.gd @@ -102,7 +102,7 @@ func _on_click(event: EventPointer): selected_room = room_name func _generate_room_map(): - var rooms = Store.house.rooms + var rooms = Store.house.state.rooms var target_size = Vector2(0.2, 0.24) var target_offset = Vector2(0, 0.05) diff --git a/app/content/ui/menu/settings/settings_menu.gd b/app/content/ui/menu/settings/settings_menu.gd index 51e3afc..226f03f 100644 --- a/app/content/ui/menu/settings/settings_menu.gd +++ b/app/content/ui/menu/settings/settings_menu.gd @@ -3,7 +3,6 @@ extends Node3D const credits_scene = preload ("./credits.tscn") @onready var connection_status = $Content/ConnectionStatus -@onready var main = $"/root/Main" @onready var input_url = $Content/InputURL @onready var input_token = $Content/InputToken @@ -15,6 +14,8 @@ const credits_scene = preload ("./credits.tscn") @onready var voice_assist = $Content/VoiceAssist func _ready(): + var settings_store = Store.settings.state + background.visible = false credits.on_click.connect(func(_event): @@ -25,12 +26,12 @@ func _ready(): ) if Store.settings.is_loaded(): - input_url.text = Store.settings.url - input_token.text = Store.settings.token + input_url.text = settings_store.url + input_token.text = settings_store.token else: Store.settings.on_loaded.connect(func(): - input_url.text=Store.settings.url - input_token.text=Store.settings.token + input_url.text=settings_store.url + input_token.text=settings_store.token ) button_connect.on_button_down.connect(func(): @@ -39,8 +40,8 @@ func _ready(): HomeApi.start_adapter("hass_ws", url, token) - Store.settings.url=url - Store.settings.token=token + settings_store.url=url + settings_store.token=token Store.settings.save_local() ) @@ -63,8 +64,7 @@ func _ready(): voice_assist.label="mic" - Store.settings.voice_assistant=true - main.update_voice_assistant() + settings_store.voice_assistant=true Store.settings.save_local() ) @@ -74,8 +74,7 @@ func _ready(): voice_assist.label="mic_off" - Store.settings.voice_assistant=false - main.update_voice_assistant() + settings_store.voice_assistant=false Store.settings.save_local() ) @@ -91,5 +90,9 @@ func _ready(): if Store.settings.is_loaded() == false: await Store.settings.on_loaded - voice_assist.label = "mic_off" if Store.settings.voice_assistant == false else "mic" - voice_assist.active = Store.settings.voice_assistant + var button_label = R.computed(func(_arg): + return "mic_off" if settings_store.voice_assistant == false else "mic" + ) + + R.bind(voice_assist, "label", button_label) + R.bind(voice_assist, "active", settings_store, "voice_assistant") diff --git a/app/content/ui/onboarding/onboarding.gd b/app/content/ui/onboarding/onboarding.gd index b30bf4d..d917341 100644 --- a/app/content/ui/onboarding/onboarding.gd +++ b/app/content/ui/onboarding/onboarding.gd @@ -9,7 +9,7 @@ func _ready(): if Store.settings.is_loaded() == false: await Store.settings.on_loaded - if (Store.settings.url != ""&&Store.settings.url != null)||Store.settings.onboarding_complete: + if (Store.settings.state.url != ""&&Store.settings.state.url != null)||Store.settings.state.onboarding_complete: close() return @@ -24,7 +24,7 @@ func _ready(): EventSystem.on_slow_tick.connect(_slow_tick) func close(): - Store.settings.onboarding_complete = true + Store.settings.state.onboarding_complete = true Store.settings.save_local() queue_free() diff --git a/app/lib/globals/home_api.gd b/app/lib/globals/home_api.gd index 1b37a7a..fbaa024 100644 --- a/app/lib/globals/home_api.gd +++ b/app/lib/globals/home_api.gd @@ -33,7 +33,8 @@ func _ready(): var success = Store.settings.load_local() if success: - start_adapter(Store.settings.type.to_lower(), Store.settings.url, Store.settings.token) + print(Store.settings) + start_adapter(Store.settings.state.type.to_lower(), Store.settings.state.url, Store.settings.state.token) ## Starts the adapter for the given type and url func start_adapter(type: String, url: String, token: String): diff --git a/app/lib/stores/settings.gd b/app/lib/stores/settings.gd index f24c16b..4ec83c2 100644 --- a/app/lib/stores/settings.gd +++ b/app/lib/stores/settings.gd @@ -22,4 +22,4 @@ func clear(): self.state.url = "" self.state.token = "" self.state.voice_assistant = false - self.state.onboarding_complete = false \ No newline at end of file + self.state.onboarding_complete = false diff --git a/app/lib/stores/store.gd b/app/lib/stores/store.gd index e00bcea..a85e1a0 100644 --- a/app/lib/stores/store.gd +++ b/app/lib/stores/store.gd @@ -24,7 +24,7 @@ func clear(): func sanitizeState(dict=state): var data = {} - for prop_info in get_property_list(): + for prop_info in state.get_property_list(): var key = prop_info.name if key.begins_with("_")||(prop_info.has("hint_string")&&prop_info.hint_string != ""): @@ -38,12 +38,12 @@ func sanitizeState(dict=state): return data func use_dict(dict: Dictionary, target=state): - for prop_info in get_property_list(): + for prop_info in state.get_property_list(): var key = prop_info.name if key.begins_with("_")||(prop_info.has("hint_string")&&prop_info.hint_string != ""): continue - + if dict.has(key) == false: continue From d07a7b924f790c3ee3587e7bb823ef743e5aaaf5 Mon Sep 17 00:00:00 2001 From: Nitwel Date: Wed, 10 Apr 2024 00:21:38 +0200 Subject: [PATCH 07/10] continue on wim --- .../animations/left/hand_blend_tree.tres | 2 +- .../animations/right/hand_blend_tree.tres | 2 +- app/content/system/house/house.gd | 4 +- app/content/system/house/house.tscn | 4 +- app/content/system/house/mini/miniature.gd | 95 ++++++++++++------- app/content/system/house/mini/miniature.tscn | 8 +- app/content/ui/components/button/button.gd | 3 + app/content/ui/menu/view/view_menu.gd | 2 +- 8 files changed, 75 insertions(+), 45 deletions(-) diff --git a/app/addons/godot-xr-tools/hands/animations/left/hand_blend_tree.tres b/app/addons/godot-xr-tools/hands/animations/left/hand_blend_tree.tres index ae6f20a..011abdb 100644 --- a/app/addons/godot-xr-tools/hands/animations/left/hand_blend_tree.tres +++ b/app/addons/godot-xr-tools/hands/animations/left/hand_blend_tree.tres @@ -29,4 +29,4 @@ nodes/OpenHand/node = SubResource("4") nodes/OpenHand/position = Vector2(-600, 100) nodes/Trigger/node = SubResource("5") nodes/Trigger/position = Vector2(-360, 20) -node_connections = [&"output", 0, &"Grip", &"Grip", 0, &"Trigger", &"Grip", 1, &"ClosedHand2", &"Trigger", 0, &"OpenHand", &"Trigger", 1, &"ClosedHand1"] +node_connections = [&"Grip", 0, &"Trigger", &"Grip", 1, &"ClosedHand2", &"Trigger", 0, &"OpenHand", &"Trigger", 1, &"ClosedHand1", &"output", 0, &"Grip"] diff --git a/app/addons/godot-xr-tools/hands/animations/right/hand_blend_tree.tres b/app/addons/godot-xr-tools/hands/animations/right/hand_blend_tree.tres index f56fb58..f1d41a1 100644 --- a/app/addons/godot-xr-tools/hands/animations/right/hand_blend_tree.tres +++ b/app/addons/godot-xr-tools/hands/animations/right/hand_blend_tree.tres @@ -29,4 +29,4 @@ nodes/OpenHand/node = SubResource("3") nodes/OpenHand/position = Vector2(-600, 100) nodes/Trigger/node = SubResource("5") nodes/Trigger/position = Vector2(-360, 40) -node_connections = [&"output", 0, &"Grip", &"Grip", 0, &"Trigger", &"Grip", 1, &"ClosedHand2", &"Trigger", 0, &"OpenHand", &"Trigger", 1, &"ClosedHand1"] +node_connections = [&"Grip", 0, &"Trigger", &"Grip", 1, &"ClosedHand2", &"Trigger", 0, &"OpenHand", &"Trigger", 1, &"ClosedHand1", &"output", 0, &"Grip"] diff --git a/app/content/system/house/house.gd b/app/content/system/house/house.gd index c5517fa..d7891c0 100644 --- a/app/content/system/house/house.gd +++ b/app/content/system/house/house.gd @@ -6,7 +6,7 @@ const RoomType = preload ("./room/room.gd") @onready var levels = $Levels @onready var collision_shape = $Levels/CollisionShape3D @onready var align_reference = $AlignReference -@onready var mini_view = $Miniature +@onready var mini_view = $Levels/Miniature var fixing_reference: bool = false var editing_room: RoomType = null @@ -23,7 +23,7 @@ func update_house(): align_reference.update_align_reference() - for index in range(Store.house.state.rooms.size() - 1, -1, -1): + for index in range(Store.house.state.rooms.size()): var new_room = Store.house.state.rooms[index] if new_room.corners.size() == 0: diff --git a/app/content/system/house/house.tscn b/app/content/system/house/house.tscn index aad1919..17f7d78 100644 --- a/app/content/system/house/house.tscn +++ b/app/content/system/house/house.tscn @@ -23,8 +23,8 @@ script = ExtResource("2_w1auk") restricted = true lock_rotation = true +[node name="Miniature" parent="Levels" instance=ExtResource("4_qjbly")] + [node name="AlignReference" parent="." instance=ExtResource("3_e1tcn")] visible = false disabled = true - -[node name="Miniature" parent="." instance=ExtResource("4_qjbly")] diff --git a/app/content/system/house/mini/miniature.gd b/app/content/system/house/mini/miniature.gd index 7cd4b08..3efc769 100644 --- a/app/content/system/house/mini/miniature.gd +++ b/app/content/system/house/mini/miniature.gd @@ -3,63 +3,88 @@ extends Node3D const ConstructRoomMesh = preload ("res://lib/utils/mesh/construct_room_mesh.gd") const wall_material = preload ("./mini_wall.tres") +@onready var body = $Body +@onready var model = $Body/Model @onready var walls_mesh = $Body/Model/WallsMesh @onready var floor_mesh = $Body/Model/FloorMesh @onready var collision_shape = $Body/CollisionShape3D -@onready var toggle_heatmap = $HeatmapButton +@onready var toggle_heatmap = $Body/HeatmapButton # var temperature_scale := Vector2( - 20.0, 60.0) -var temperature_scale := Vector2(22.0, 25.0) +var temperature_scale := Vector2(22.0, 26.0) -var enabled = true: - set(value): - enabled = value - update() +var heatmap = R.state(false) +var small = R.state(false) func _ready(): - update() - if Store.house.is_loaded() == false: await Store.house.on_loaded - if Store.house.state.rooms.size() == 0: - return + R.effect(func(_arg): + if Store.house.state.rooms.size() == 0: + return - var room = Store.house.state.rooms[0] + if heatmap.value == false: + return - var corners = room.corners - var height = room.height + for room in Store.house.state.rooms: + var corners=room.corners + var height=room.height - walls_mesh.mesh = ConstructRoomMesh.generate_wall_mesh_grid(corners, height) - floor_mesh.mesh = ConstructRoomMesh.generate_ceiling_mesh_grid(corners) + walls_mesh.mesh=ConstructRoomMesh.generate_wall_mesh_grid(corners, height) + floor_mesh.mesh=ConstructRoomMesh.generate_ceiling_mesh_grid(corners) - walls_mesh.material_override = wall_material - floor_mesh.material_override = wall_material - - active = true - EventSystem.on_slow_tick.connect(update_data) - - toggle_heatmap.on_button_down.connect(func(): - active=true - EventSystem.on_slow_tick.connect(update_data) + walls_mesh.material_override=wall_material + floor_mesh.material_override=wall_material ) - toggle_heatmap.on_button_up.connect(func(): - wall_material.set_shader_parameter("data", []) - wall_material.set_shader_parameter("data_size", 0) - active=false - EventSystem.on_slow_tick.disconnect(update_data) + R.bind(toggle_heatmap, "active", heatmap, toggle_heatmap.on_toggled) + + R.effect(func(_arg): + var tween:=create_tween() + tween.set_parallel(true) + if small.value: + + var aabb=House.body.get_level_aabb(0) + aabb.position.y=- 0.03 + aabb.size.y=0.06 + + var center=aabb.position + aabb.size / 2 + + collision_shape.shape.size=aabb.size * 0.1 + + var camera=$"/root/Main/XROrigin3D/XRCamera3D" + var camera_position=camera.global_position + var camera_direction=- camera.global_transform.basis.z + + camera_position.y *= 0.5 + camera_direction.y=0 + + var target_position=camera_position + camera_direction.normalized() * 0.2 + var new_position=target_position - center * 0.1 + + tween.tween_property(model, "scale", Vector3(0.1, 0.1, 0.1), 0.5) + tween.tween_property(body, "position", new_position, 0.5) + else: + tween.tween_property(model, "scale", Vector3(1, 1, 1), 0.5) + tween.tween_property(body, "position", Vector3(0, 0, 0), 0.5) ) -func update(): - walls_mesh.visible = enabled - floor_mesh.visible = enabled - collision_shape.disabled = not enabled + R.effect(func(_arg): + walls_mesh.visible=heatmap.value + floor_mesh.visible=heatmap.value + collision_shape.disabled=!heatmap.value + + if heatmap.value: + EventSystem.on_slow_tick.connect(update_data) + else: + EventSystem.on_slow_tick.disconnect(update_data) + wall_material.set_shader_parameter("data", []) + wall_material.set_shader_parameter("data_size", 0) + ) const SensorEntity = preload ("res://content/entities/sensor/sensor.gd") -var active: bool = false - func update_data(_delta: float) -> void: var data_list = [] diff --git a/app/content/system/house/mini/miniature.tscn b/app/content/system/house/mini/miniature.tscn index 1ae4bd5..eba1d0d 100644 --- a/app/content/system/house/mini/miniature.tscn +++ b/app/content/system/house/mini/miniature.tscn @@ -9,9 +9,6 @@ [node name="Miniature" type="Node3D"] script = ExtResource("1_b53yn") -[node name="HeatmapButton" parent="." instance=ExtResource("3_tgdcf")] -toggleable = true - [node name="Body" type="StaticBody3D" parent="."] [node name="CollisionShape3D" type="CollisionShape3D" parent="Body"] @@ -27,3 +24,8 @@ skeleton = NodePath("../../..") [node name="FloorMesh" type="MeshInstance3D" parent="Body/Model"] skeleton = NodePath("../../..") + +[node name="HeatmapButton" parent="Body" instance=ExtResource("3_tgdcf")] +label = "heat" +icon = true +toggleable = true diff --git a/app/content/ui/components/button/button.gd b/app/content/ui/components/button/button.gd index 71ccca3..4fc6ff9 100644 --- a/app/content/ui/components/button/button.gd +++ b/app/content/ui/components/button/button.gd @@ -5,6 +5,7 @@ class_name Button3D signal on_button_down() signal on_button_up() +signal on_toggled(active: bool) const IconFont = preload ("res://assets/icons/icons.tres") const ECHO_WAIT_INITIAL = 0.5 @@ -57,6 +58,8 @@ const ECHO_WAIT_REPEAT = 0.1 var active: bool = false: set(value): + if active != value: + on_toggled.emit(value) active = value if !is_inside_tree(): return update_animation(1.0 if active else 0.0) diff --git a/app/content/ui/menu/view/view_menu.gd b/app/content/ui/menu/view/view_menu.gd index 4324da8..0eab8fb 100644 --- a/app/content/ui/menu/view/view_menu.gd +++ b/app/content/ui/menu/view/view_menu.gd @@ -7,5 +7,5 @@ func _ready(): background.visible = false mini_view.on_button_down.connect(func(): - House.body.mini_view.enabled=!House.body.mini_view.enabled + House.body.mini_view.small.value=!House.body.mini_view.small.value ) From 3e84b04c6758828fcdeecdc237880233ac20c38d Mon Sep 17 00:00:00 2001 From: Nitwel Date: Wed, 10 Apr 2024 13:23:17 +0200 Subject: [PATCH 08/10] finish basic mini view and heatmap part --- app/content/main.gd | 2 +- app/content/system/house/house.gd | 6 +- .../house/mini/mini_wall_shader.gdshader | 25 ++++---- app/content/system/house/mini/miniature.gd | 64 +++++++++++++------ app/content/system/house/mini/miniature.tscn | 14 +--- app/content/ui/components/button/button.gd | 6 +- app/content/ui/menu/view/view_menu.gd | 39 ++++++++++- app/content/ui/menu/view/view_menu.tscn | 41 +++++++++++- app/lib/globals/house_body.gd | 4 +- 9 files changed, 148 insertions(+), 53 deletions(-) diff --git a/app/content/main.gd b/app/content/main.gd index 75a43b2..86af213 100644 --- a/app/content/main.gd +++ b/app/content/main.gd @@ -47,7 +47,7 @@ func _ready(): if action.name == "menu_button": toggle_menu() elif action.name == "by_button": - House.body.mini_view=!House.body.mini_view + House.body.mini_view.small.value=!House.body.mini_view.small.value ) EventSystem.on_focus_in.connect(func(event): diff --git a/app/content/system/house/house.gd b/app/content/system/house/house.gd index d7891c0..92b2877 100644 --- a/app/content/system/house/house.gd +++ b/app/content/system/house/house.gd @@ -2,11 +2,13 @@ extends Node3D const Room = preload ("./room/room.tscn") const RoomType = preload ("./room/room.gd") +const Miniature = preload ("./mini/miniature.gd") +const AlignReference = preload ("./align_reference.gd") @onready var levels = $Levels @onready var collision_shape = $Levels/CollisionShape3D -@onready var align_reference = $AlignReference -@onready var mini_view = $Levels/Miniature +@onready var align_reference: AlignReference = $AlignReference +@onready var mini_view: Miniature = $Levels/Miniature var fixing_reference: bool = false var editing_room: RoomType = null diff --git a/app/content/system/house/mini/mini_wall_shader.gdshader b/app/content/system/house/mini/mini_wall_shader.gdshader index 0af72f6..34e3bf1 100644 --- a/app/content/system/house/mini/mini_wall_shader.gdshader +++ b/app/content/system/house/mini/mini_wall_shader.gdshader @@ -18,27 +18,28 @@ float sphere_weight(int index, vec3 world_pos, float r) { } void vertex() { - // Calculate Global Coordinates - vec3 world_position = (MODEL_MATRIX * vec4(VERTEX, 1.0)).xyz; - color = vec3(1.0, 1.0, 1.0); - float distances[100]; - float dist_sum = 0.0; - float data_sum = 0.0; - - float closest_dist = -1.0; - int closest_index = 0; if(data_size > 0) { - closest_dist = distance(data[0].xyz, world_position); + float distances[100]; + float dist_sum = 0.0; + float data_sum = 0.0; + + float closest_dist = -1.0; + int closest_index = 0; + + // Calculate Global Coordinates + //vec3 world_position = (MODEL_MATRIX * vec4(VERTEX, 1.0)).xyz; + + closest_dist = distance(data[0].xyz, VERTEX); // Inverse distance weighting using Shepard's method for(int i = 0; i < data_size; i++) { - distances[i] = sphere_weight(i, world_position, 5.0); + distances[i] = sphere_weight(i, VERTEX, 5.0); dist_sum += distances[i]; data_sum += distances[i] * data[i].w; - float dist = distance(data[i].xyz, world_position); + float dist = distance(data[i].xyz, VERTEX); if(dist < closest_dist) { closest_dist = dist; diff --git a/app/content/system/house/mini/miniature.gd b/app/content/system/house/mini/miniature.gd index 3efc769..1a97d62 100644 --- a/app/content/system/house/mini/miniature.gd +++ b/app/content/system/house/mini/miniature.gd @@ -5,42 +5,58 @@ const wall_material = preload ("./mini_wall.tres") @onready var body = $Body @onready var model = $Body/Model -@onready var walls_mesh = $Body/Model/WallsMesh -@onready var floor_mesh = $Body/Model/FloorMesh @onready var collision_shape = $Body/CollisionShape3D @onready var toggle_heatmap = $Body/HeatmapButton +enum HeatmapType { + NONE = 0, + TEMPERATURE = 1, + HUMIDITY = 2 +} + # var temperature_scale := Vector2( - 20.0, 60.0) var temperature_scale := Vector2(22.0, 26.0) -var heatmap = R.state(false) +var heatmap_type = R.state(HeatmapType.NONE) var small = R.state(false) func _ready(): + wall_material.set_shader_parameter("data", []) + wall_material.set_shader_parameter("data_size", 0) + if Store.house.is_loaded() == false: await Store.house.on_loaded + # Update Room Mesh R.effect(func(_arg): if Store.house.state.rooms.size() == 0: return - if heatmap.value == false: + if heatmap_type.value == HeatmapType.NONE&&small.value == false: return - for room in Store.house.state.rooms: - var corners=room.corners - var height=room.height + for child in model.get_children(): + model.remove_child(child) + child.free() - walls_mesh.mesh=ConstructRoomMesh.generate_wall_mesh_grid(corners, height) - floor_mesh.mesh=ConstructRoomMesh.generate_ceiling_mesh_grid(corners) + for room in Store.house.state.rooms: + var walls_mesh=MeshInstance3D.new() + var floor_mesh=MeshInstance3D.new() + + model.add_child(walls_mesh) + model.add_child(floor_mesh) + + walls_mesh.mesh=ConstructRoomMesh.generate_wall_mesh_grid(room.corners, room.height) + floor_mesh.mesh=ConstructRoomMesh.generate_ceiling_mesh_grid(room.corners) walls_mesh.material_override=wall_material floor_mesh.material_override=wall_material ) - R.bind(toggle_heatmap, "active", heatmap, toggle_heatmap.on_toggled) - + # Update Size R.effect(func(_arg): + collision_shape.disabled=small.value == false + var tween:=create_tween() tween.set_parallel(true) if small.value: @@ -66,16 +82,23 @@ func _ready(): tween.tween_property(model, "scale", Vector3(0.1, 0.1, 0.1), 0.5) tween.tween_property(body, "position", new_position, 0.5) else: - tween.tween_property(model, "scale", Vector3(1, 1, 1), 0.5) - tween.tween_property(body, "position", Vector3(0, 0, 0), 0.5) + tween.tween_property(model, "scale", Vector3.ONE, 0.5) + tween.tween_property(body, "position", Vector3.ZERO, 0.5) + tween.tween_property(body, "quaternion", Quaternion.IDENTITY, 0.5) ) + # Update Walls R.effect(func(_arg): - walls_mesh.visible=heatmap.value - floor_mesh.visible=heatmap.value - collision_shape.disabled=!heatmap.value + var show_map=heatmap_type.value != HeatmapType.NONE + var show_small=small.value - if heatmap.value: + for child in model.get_children(): + child.visible=show_map||show_small + ) + + # Update Heatmap + R.effect(func(_arg): + if heatmap_type.value != HeatmapType.NONE: EventSystem.on_slow_tick.connect(update_data) else: EventSystem.on_slow_tick.disconnect(update_data) @@ -85,6 +108,11 @@ func _ready(): const SensorEntity = preload ("res://content/entities/sensor/sensor.gd") +# func _process(delta): +# for mesh in model.get_children(): +# if mesh is MeshInstance3D: +# mesh.material_override.set_shader_parameter("mesh_pos", + func update_data(_delta: float) -> void: var data_list = [] @@ -96,7 +124,7 @@ func update_data(_delta: float) -> void: if data == null: continue - var sensor_pos = sensor.global_position + var sensor_pos = House.body.to_local(sensor.global_position) data_list.append(Vector4(sensor_pos.x, sensor_pos.y, sensor_pos.z, float(data))) diff --git a/app/content/system/house/mini/miniature.tscn b/app/content/system/house/mini/miniature.tscn index eba1d0d..885837a 100644 --- a/app/content/system/house/mini/miniature.tscn +++ b/app/content/system/house/mini/miniature.tscn @@ -1,8 +1,7 @@ -[gd_scene load_steps=5 format=3 uid="uid://ds60i5n211hi3"] +[gd_scene load_steps=4 format=3 uid="uid://ds60i5n211hi3"] [ext_resource type="Script" path="res://content/system/house/mini/miniature.gd" id="1_b53yn"] [ext_resource type="Script" path="res://content/functions/movable.gd" id="2_x7oed"] -[ext_resource type="PackedScene" uid="uid://bsjqdvkt0u87c" path="res://content/ui/components/button/button.tscn" id="3_tgdcf"] [sub_resource type="BoxShape3D" id="BoxShape3D_bckw3"] @@ -18,14 +17,3 @@ shape = SubResource("BoxShape3D_bckw3") script = ExtResource("2_x7oed") [node name="Model" type="Node3D" parent="Body"] - -[node name="WallsMesh" type="MeshInstance3D" parent="Body/Model"] -skeleton = NodePath("../../..") - -[node name="FloorMesh" type="MeshInstance3D" parent="Body/Model"] -skeleton = NodePath("../../..") - -[node name="HeatmapButton" parent="Body" instance=ExtResource("3_tgdcf")] -label = "heat" -icon = true -toggleable = true diff --git a/app/content/ui/components/button/button.gd b/app/content/ui/components/button/button.gd index 4fc6ff9..740f69e 100644 --- a/app/content/ui/components/button/button.gd +++ b/app/content/ui/components/button/button.gd @@ -58,8 +58,10 @@ const ECHO_WAIT_REPEAT = 0.1 var active: bool = false: set(value): - if active != value: - on_toggled.emit(value) + if active == value: + return + + on_toggled.emit(value) active = value if !is_inside_tree(): return update_animation(1.0 if active else 0.0) diff --git a/app/content/ui/menu/view/view_menu.gd b/app/content/ui/menu/view/view_menu.gd index 0eab8fb..d22a003 100644 --- a/app/content/ui/menu/view/view_menu.gd +++ b/app/content/ui/menu/view/view_menu.gd @@ -1,11 +1,44 @@ extends Node3D -@onready var mini_view = $Content/MiniView +const Miniature = preload ("res://content/system/house/mini/miniature.gd") + +@onready var mini_view_button = $Content/MiniView +@onready var heat_map_button = $Content/HeatMap +@onready var humudity_map_button = $Content/HumidityMap @onready var background = $Background func _ready(): background.visible = false - mini_view.on_button_down.connect(func(): - House.body.mini_view.small.value=!House.body.mini_view.small.value + if !House.body.is_node_ready(): + await House.body.ready + + var mini_view = House.body.mini_view + + mini_view_button.on_toggled.connect(func(active): + mini_view.small.value=active + ) + + heat_map_button.on_toggled.connect(func(active): + if active == false: + if mini_view.heatmap_type.value == Miniature.HeatmapType.TEMPERATURE: + mini_view.heatmap_type.value=Miniature.HeatmapType.NONE + return + + mini_view.heatmap_type.value=Miniature.HeatmapType.TEMPERATURE + ) + + humudity_map_button.on_toggled.connect(func(active): + if active == false: + if mini_view.heatmap_type.value == Miniature.HeatmapType.HUMIDITY: + mini_view.heatmap_type.value=Miniature.HeatmapType.NONE + return + + mini_view.heatmap_type.value=Miniature.HeatmapType.HUMIDITY + ) + + R.effect(func(_arg): + heat_map_button.active=mini_view.heatmap_type.value == Miniature.HeatmapType.TEMPERATURE + humudity_map_button.active=mini_view.heatmap_type.value == Miniature.HeatmapType.HUMIDITY + ) diff --git a/app/content/ui/menu/view/view_menu.tscn b/app/content/ui/menu/view/view_menu.tscn index 986c50b..a69710f 100644 --- a/app/content/ui/menu/view/view_menu.tscn +++ b/app/content/ui/menu/view/view_menu.tscn @@ -1,7 +1,8 @@ -[gd_scene load_steps=4 format=3 uid="uid://ddpxthb414unp"] +[gd_scene load_steps=5 format=3 uid="uid://ddpxthb414unp"] [ext_resource type="Script" path="res://content/ui/menu/view/view_menu.gd" id="1_hxajx"] [ext_resource type="PackedScene" uid="uid://bsjqdvkt0u87c" path="res://content/ui/components/button/button.tscn" id="2_qan1b"] +[ext_resource type="Material" uid="uid://bujy3egn1oqac" path="res://assets/materials/pri-500.material" id="2_se6ic"] [sub_resource type="BoxMesh" id="BoxMesh_qr3bi"] size = Vector3(0.3, 0.01, 0.3) @@ -11,6 +12,7 @@ script = ExtResource("1_hxajx") [node name="Background" type="MeshInstance3D" parent="."] transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0.15, 0, 0.15) +material_override = ExtResource("2_se6ic") mesh = SubResource("BoxMesh_qr3bi") [node name="Content" type="Node3D" parent="."] @@ -19,3 +21,40 @@ mesh = SubResource("BoxMesh_qr3bi") transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0.03, 0, 0.03) label = "view_comfy" icon = true +toggleable = true + +[node name="MiniViewLabel" type="Label3D" parent="Content"] +transform = Transform3D(1, 0, 0, 0, 0, 1, 0, -1, 0, 0.07, 0.01, 0.03) +pixel_size = 0.001 +text = "Mini View" +font_size = 18 +outline_size = 0 +horizontal_alignment = 0 + +[node name="HeatMap" parent="Content" instance=ExtResource("2_qan1b")] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0.03, 0, 0.09) +label = "device_thermostat" +icon = true +toggleable = true + +[node name="HeatMapLabel" type="Label3D" parent="Content"] +transform = Transform3D(1, 0, 0, 0, 0, 1, 0, -1, 0, 0.07, 0.01, 0.09) +pixel_size = 0.001 +text = "Heat Map" +font_size = 18 +outline_size = 0 +horizontal_alignment = 0 + +[node name="HumidityMap" parent="Content" instance=ExtResource("2_qan1b")] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0.03, 0, 0.15) +label = "humidity_mid" +icon = true +toggleable = true + +[node name="HumidityMapLabel" type="Label3D" parent="Content"] +transform = Transform3D(1, 0, 0, 0, 0, 1, 0, -1, 0, 0.07, 0.01, 0.15) +pixel_size = 0.001 +text = "Humidity Map" +font_size = 18 +outline_size = 0 +horizontal_alignment = 0 diff --git a/app/lib/globals/house_body.gd b/app/lib/globals/house_body.gd index 5ea5d3c..2339687 100644 --- a/app/lib/globals/house_body.gd +++ b/app/lib/globals/house_body.gd @@ -1,4 +1,6 @@ extends Node ## Shortcut to get the House node from the Main scene -@onready var body = get_node_or_null("/root/Main/House") \ No newline at end of file +const HouseClass = preload ("res://content/system/house/house.gd") + +@onready var body: HouseClass = get_node_or_null("/root/Main/House") \ No newline at end of file From 139d9466ffaba29ac9c4bbe9eb1d8ea04ccefd5c Mon Sep 17 00:00:00 2001 From: Nitwel Date: Wed, 10 Apr 2024 15:59:27 +0200 Subject: [PATCH 09/10] finish up heat and humidity in mini view --- app/content/entities/sensor/sensor.gd | 8 ++ .../system/house/mini/humid_gradient.tres | 11 ++ app/content/system/house/mini/mini_wall.tres | 15 +-- .../house/mini/mini_wall_shader.gdshader | 2 +- app/content/system/house/mini/miniature.gd | 69 ++++++++++-- .../system/house/mini/temp_gradient.tres | 11 ++ app/content/system/house/room/states/edit.gd | 102 +++++++++--------- app/content/ui/menu/view/view_menu.gd | 51 ++++++++- app/content/ui/menu/view/view_menu.tscn | 48 ++++++++- 9 files changed, 242 insertions(+), 75 deletions(-) create mode 100644 app/content/system/house/mini/humid_gradient.tres create mode 100644 app/content/system/house/mini/temp_gradient.tres diff --git a/app/content/entities/sensor/sensor.gd b/app/content/entities/sensor/sensor.gd index c7c49f5..cb82054 100644 --- a/app/content/entities/sensor/sensor.gd +++ b/app/content/entities/sensor/sensor.gd @@ -6,6 +6,7 @@ const Entity = preload ("../entity.gd") @onready var collision_shape = $CollisionShape3D var sensor_data = {} +var unit = null # Called when the node enters the scene tree for the first time. func _ready(): @@ -28,6 +29,7 @@ func set_text(stateInfo): text = stateInfo["attributes"]["friendly_name"] + "\n" + text if stateInfo["attributes"].has("unit_of_measurement")&&stateInfo["attributes"]["unit_of_measurement"] != null: + unit = stateInfo["attributes"]["unit_of_measurement"] text += " " + stateInfo["attributes"]["unit_of_measurement"] if stateInfo["attributes"].has("device_class"): @@ -49,3 +51,9 @@ func get_sensor_data(type: String): return null return sensor_data[type] + +func get_sensor_unit(type: String): + if sensor_data.has(type) == false: + return null + + return unit diff --git a/app/content/system/house/mini/humid_gradient.tres b/app/content/system/house/mini/humid_gradient.tres new file mode 100644 index 0000000..ac40fcb --- /dev/null +++ b/app/content/system/house/mini/humid_gradient.tres @@ -0,0 +1,11 @@ +[gd_resource type="GradientTexture1D" load_steps=2 format=3 uid="uid://gfemvrlwowg7"] + +[sub_resource type="Gradient" id="Gradient_2jwis"] +interpolation_color_space = 2 +offsets = PackedFloat32Array(0, 0.333333, 0.5, 1) +colors = PackedColorArray(0.999396, 0, 0.058647, 1, 1, 0.85, 0, 1, 0, 0.95, 1, 1, 0.0333333, 0, 1, 1) +metadata/_snap_enabled = true +metadata/_snap_count = 6 + +[resource] +gradient = SubResource("Gradient_2jwis") diff --git a/app/content/system/house/mini/mini_wall.tres b/app/content/system/house/mini/mini_wall.tres index ea81d20..d8f483f 100644 --- a/app/content/system/house/mini/mini_wall.tres +++ b/app/content/system/house/mini/mini_wall.tres @@ -1,16 +1,7 @@ -[gd_resource type="ShaderMaterial" load_steps=4 format=3 uid="uid://bcfcough6ucvc"] +[gd_resource type="ShaderMaterial" load_steps=3 format=3 uid="uid://bcfcough6ucvc"] [ext_resource type="Shader" path="res://content/system/house/mini/mini_wall_shader.gdshader" id="1_sbr3e"] - -[sub_resource type="Gradient" id="Gradient_2jwis"] -interpolation_color_space = 2 -offsets = PackedFloat32Array(0.00840336, 0.1, 0.4375, 0.5625, 1) -colors = PackedColorArray(0.533333, 0, 1, 1, 0, 0.45, 1, 1, 0, 0.95, 1, 1, 0.983333, 1, 0, 1, 0.999396, 0, 0.058647, 1) -metadata/_snap_enabled = true -metadata/_snap_count = 16 - -[sub_resource type="GradientTexture1D" id="GradientTexture1D_rrsal"] -gradient = SubResource("Gradient_2jwis") +[ext_resource type="Texture2D" uid="uid://bbuq4wn7e5o2q" path="res://content/system/house/mini/temp_gradient.tres" id="2_3lwi8"] [resource] render_priority = 0 @@ -18,4 +9,4 @@ shader = ExtResource("1_sbr3e") shader_parameter/data = PackedFloat32Array() shader_parameter/data_size = 0 shader_parameter/alpha = 0.3 -shader_parameter/color_gradient = SubResource("GradientTexture1D_rrsal") +shader_parameter/color_gradient = ExtResource("2_3lwi8") diff --git a/app/content/system/house/mini/mini_wall_shader.gdshader b/app/content/system/house/mini/mini_wall_shader.gdshader index 34e3bf1..b11c4e6 100644 --- a/app/content/system/house/mini/mini_wall_shader.gdshader +++ b/app/content/system/house/mini/mini_wall_shader.gdshader @@ -59,5 +59,5 @@ void vertex() { void fragment() { ALBEDO = vec3(color.xyz); - ALPHA = 0.3; + ALPHA = alpha; } diff --git a/app/content/system/house/mini/miniature.gd b/app/content/system/house/mini/miniature.gd index 1a97d62..688e2fe 100644 --- a/app/content/system/house/mini/miniature.gd +++ b/app/content/system/house/mini/miniature.gd @@ -3,6 +3,9 @@ extends Node3D const ConstructRoomMesh = preload ("res://lib/utils/mesh/construct_room_mesh.gd") const wall_material = preload ("./mini_wall.tres") +const humidity_gradient = preload ("./humid_gradient.tres") +const temperature_gradient = preload ("./temp_gradient.tres") + @onready var body = $Body @onready var model = $Body/Model @onready var collision_shape = $Body/CollisionShape3D @@ -14,9 +17,19 @@ enum HeatmapType { HUMIDITY = 2 } -# var temperature_scale := Vector2( - 20.0, 60.0) -var temperature_scale := Vector2(22.0, 26.0) +var heatmap_type_strings = { + HeatmapType.NONE: "none", + HeatmapType.TEMPERATURE: "temperature", + HeatmapType.HUMIDITY: "humidity" +} +var base_scale = { + HeatmapType.NONE: Vector2(0.0, 1.0), + HeatmapType.TEMPERATURE: Vector2( - 20.0, 60.0), + HeatmapType.HUMIDITY: Vector2(0.0, 100.0) +} +var selected_scale = R.state(Vector2(0.0, 1.0)) +var opacity = R.state(30) var heatmap_type = R.state(HeatmapType.NONE) var small = R.state(false) @@ -100,27 +113,33 @@ func _ready(): R.effect(func(_arg): if heatmap_type.value != HeatmapType.NONE: EventSystem.on_slow_tick.connect(update_data) + if heatmap_type.value == HeatmapType.TEMPERATURE: + wall_material.set_shader_parameter("color_gradient", temperature_gradient) + else: + wall_material.set_shader_parameter("color_gradient", humidity_gradient) else: EventSystem.on_slow_tick.disconnect(update_data) wall_material.set_shader_parameter("data", []) wall_material.set_shader_parameter("data_size", 0) ) + R.effect(func(_arg): + wall_material.set_shader_parameter("alpha", opacity.value / 100.0) + ) + const SensorEntity = preload ("res://content/entities/sensor/sensor.gd") -# func _process(delta): -# for mesh in model.get_children(): -# if mesh is MeshInstance3D: -# mesh.material_override.set_shader_parameter("mesh_pos", +func get_base_scale() -> Vector2: + return base_scale[heatmap_type.value] -func update_data(_delta: float) -> void: +func get_sensor_data(): var data_list = [] for room in House.body.get_rooms(0): for entity in room.get_node("Entities").get_children(): if entity is SensorEntity: var sensor = entity as SensorEntity - var data = sensor.get_sensor_data("temperature") + var data = sensor.get_sensor_data(heatmap_type_strings[heatmap_type.value]) if data == null: continue @@ -128,8 +147,40 @@ func update_data(_delta: float) -> void: data_list.append(Vector4(sensor_pos.x, sensor_pos.y, sensor_pos.z, float(data))) + return data_list + +func get_sensor_unit(): + for room in House.body.get_rooms(0): + for entity in room.get_node("Entities").get_children(): + if entity is SensorEntity: + var sensor = entity as SensorEntity + var sensor_unit = sensor.get_sensor_unit(heatmap_type_strings[heatmap_type.value]) + if sensor_unit != null: + return sensor_unit + + return "" + +func get_sensor_scale(): + var data = get_sensor_data() + var minmax + + for sensor in data: + if minmax == null: + minmax = Vector2(sensor.w, sensor.w) + else: + minmax.x = min(sensor.w, minmax.x) + minmax.y = max(sensor.w, minmax.y) + + if minmax == null: + return Vector2(0.0, 1.0) + + return minmax + +func update_data(_delta: float) -> void: + var data_list = get_sensor_data() + data_list = data_list.map(func(data: Vector4) -> Vector4: - data.w=(data.w - temperature_scale.x) / (temperature_scale.y - temperature_scale.x) + data.w=clamp((data.w - selected_scale.value.x) / (selected_scale.value.y - selected_scale.value.x), 0.0, 1.0) return data ) diff --git a/app/content/system/house/mini/temp_gradient.tres b/app/content/system/house/mini/temp_gradient.tres new file mode 100644 index 0000000..c55abeb --- /dev/null +++ b/app/content/system/house/mini/temp_gradient.tres @@ -0,0 +1,11 @@ +[gd_resource type="GradientTexture1D" load_steps=2 format=3 uid="uid://bbuq4wn7e5o2q"] + +[sub_resource type="Gradient" id="Gradient_2jwis"] +interpolation_color_space = 2 +offsets = PackedFloat32Array(0.00840336, 0.1, 0.4375, 0.5625, 1) +colors = PackedColorArray(0.533333, 0, 1, 1, 0, 0.45, 1, 1, 0, 0.95, 1, 1, 0.983333, 1, 0, 1, 0.999396, 0, 0.058647, 1) +metadata/_snap_enabled = true +metadata/_snap_count = 16 + +[resource] +gradient = SubResource("Gradient_2jwis") diff --git a/app/content/system/house/room/states/edit.gd b/app/content/system/house/room/states/edit.gd index e17a000..b11fb4f 100644 --- a/app/content/system/house/room/states/edit.gd +++ b/app/content/system/house/room/states/edit.gd @@ -1,8 +1,8 @@ extends RoomState -const wall_corner_scene = preload("../wall_corner.tscn") -const wall_edge_scene = preload("../wall_edge.tscn") -const RoomState = preload("./room_state.gd") +const wall_corner_scene = preload ("../wall_corner.tscn") +const wall_edge_scene = preload ("../wall_edge.tscn") +const RoomState = preload ("./room_state.gd") var moving = null var deleting: bool = false @@ -27,7 +27,7 @@ func _on_enter(): for i in range(1, corners.size()): add_corner(room.to_local(Vector3(corners[i].x, 0, corners[i].y))) - room.room_ceiling.get_node("CollisionShape3D").disabled = (floor_corner == null && height_corner == null) + room.room_ceiling.get_node("CollisionShape3D").disabled = (floor_corner == null&&height_corner == null) room.room_floor.get_node("CollisionShape3D").disabled = false var ceiling_shape = WorldBoundaryShape3D.new() @@ -73,7 +73,7 @@ func remove_corner(index: int): get_edge(index).queue_free() func _on_click_floor(event): - if floor_corner != null && height_corner != null: + if floor_corner != null&&height_corner != null: return add_floor_corner(event.ray.get_collision_point()) @@ -81,7 +81,7 @@ func _on_click_floor(event): room.room_ceiling.get_node("CollisionShape3D").disabled = false func _on_click_ceiling(event): - if floor_corner == null || height_corner == null || event.target != room.room_ceiling: + if floor_corner == null||height_corner == null||event.target != room.room_ceiling: return var pos = event.ray.get_collision_point() @@ -97,39 +97,39 @@ func add_floor_corner(position: Vector3): height_edge.align_to_corners(position, position + Vector3.UP * room.room_ceiling.position.y) floor_corner.get_node("Clickable").on_grab_down.connect(func(event): - if !is_active() || moving != null: + if !is_active()||moving != null: return - moving = event.target + moving=event.target ) floor_corner.get_node("Clickable").on_grab_move.connect(func(event): if moving == null: return - var moving_index = height_corner.get_index() - var direction = -event.ray.global_transform.basis.z - var new_position = room.room_floor.get_node("CollisionShape3D").shape.plane.intersects_ray(event.ray.global_position, direction) + var moving_index=height_corner.get_index() + var direction=- event.ray.global_transform.basis.z + var new_position=room.room_floor.get_node("CollisionShape3D").shape.plane.intersects_ray(event.ray.global_position, direction) if new_position == null: return - moving.position = new_position + moving.position=new_position height_edge.align_to_corners(new_position, new_position + Vector3.UP * room.room_ceiling.global_position.y) - get_corner(moving_index).position.x = new_position.x - get_corner(moving_index).position.z = new_position.z + get_corner(moving_index).position.x=new_position.x + get_corner(moving_index).position.z=new_position.z if room.wall_edges.get_child_count() == 0: return get_edge(moving_index).align_to_corners(new_position, get_corner(moving_index + 1).position) - get_edge(moving_index - 1).align_to_corners(get_corner(moving_index - 1).position, new_position) + get_edge(moving_index - 1).align_to_corners(get_corner(moving_index - 1).position, new_position) ) floor_corner.get_node("Clickable").on_grab_up.connect(func(_event): - moving = null + moving=null ) room.add_child(floor_corner) @@ -141,96 +141,95 @@ func add_height_corner(position: Vector3): height_corner.position.z = position.z height_corner.get_node("Clickable").on_grab_down.connect(func(event): - if !is_active() || moving != null: + if !is_active()||moving != null: return - moving = event.target + moving=event.target ) height_corner.get_node("Clickable").on_grab_move.connect(func(event): if moving == null: return - var direction = -event.ray.global_transform.basis.z - var plane_direction = direction - plane_direction.y = 0 - plane_direction = plane_direction.normalized() * -1 + var direction=- event.ray.global_transform.basis.z + var plane_direction=direction + plane_direction.y=0 + plane_direction=plane_direction.normalized() * - 1 - var plane = Plane(plane_direction, moving.position) + var plane=Plane(plane_direction, moving.position) - var new_position = plane.intersects_ray(event.ray.global_position, direction) + var new_position=plane.intersects_ray(event.ray.global_position, direction) if new_position == null: return - room.room_ceiling.position.y = new_position.y + room.room_ceiling.position.y=new_position.y height_edge.align_to_corners(floor_corner.position, floor_corner.position + Vector3.UP * room.room_ceiling.position.y) ) height_corner.get_node("Clickable").on_grab_up.connect(func(_event): - moving = null + moving=null ) room.wall_corners.add_child(height_corner) -func add_corner(position: Vector3, index: int = -1): +func add_corner(position: Vector3, index: int=- 1): var corner = wall_corner_scene.instantiate() corner.position.x = position.x corner.position.z = position.z corner.get_node("Clickable").on_grab_down.connect(func(event): - if !is_active() || moving != null: + if !is_active()||moving != null: return - moving = event.target + moving=event.target ) corner.get_node("Clickable").on_grab_move.connect(func(event): if moving == null: return - var moving_index = moving.get_index() - var direction = -event.ray.global_transform.basis.z - var ceiling_plane = Plane(Vector3.DOWN, room.room_ceiling.global_position) - var new_position = ceiling_plane.intersects_ray(event.ray.global_position, direction) + var moving_index=moving.get_index() + var direction=- event.ray.global_transform.basis.z + var ceiling_plane=Plane(Vector3.DOWN, room.room_ceiling.global_position) + var new_position=ceiling_plane.intersects_ray(event.ray.global_position, direction) if new_position == null: - deleting = true + deleting=true - new_position = event.ray.global_position + direction + new_position=event.ray.global_position + direction - get_corner(moving_index).global_position = new_position + get_corner(moving_index).global_position=new_position if room.wall_edges.get_child_count() == 0: return get_edge(moving_index).align_to_corners(get_corner(moving_index - 1).position, get_corner(moving_index + 1).position) - get_edge(moving_index - 1).transform = get_edge(moving_index).transform + get_edge(moving_index - 1).transform=get_edge(moving_index).transform return - deleting = false + deleting=false - new_position.y = 0 + new_position.y=0 - moving.position = new_position - + moving.position=new_position if room.wall_edges.get_child_count() == 0: return get_edge(moving_index).align_to_corners(new_position, get_corner(moving_index + 1).position) - get_edge(moving_index - 1).align_to_corners(get_corner(moving_index - 1).position, new_position) + get_edge(moving_index - 1).align_to_corners(get_corner(moving_index - 1).position, new_position) ) corner.get_node("Clickable").on_grab_up.connect(func(_event): if deleting: - var moving_index = moving.get_index() + var moving_index=moving.get_index() remove_corner(moving_index) - moving = null - deleting = false + moving=null + deleting=false ) room.wall_corners.add_child(corner) @@ -243,22 +242,20 @@ func add_corner(position: Vector3, index: int = -1): if num_corners > 2: if num_corners != room.wall_edges.get_child_count(): - add_edge(get_corner(-2).position, get_corner(-1).position, -2) + add_edge(get_corner( - 2).position, get_corner( - 1).position, -2) else: get_edge(index - 1).align_to_corners(get_corner(index - 1).position, position) - -func add_edge(from_pos: Vector3, to_pos: Vector3, index: int = -1): +func add_edge(from_pos: Vector3, to_pos: Vector3, index: int=- 1): var edge: StaticBody3D = wall_edge_scene.instantiate() edge.align_to_corners(from_pos, to_pos) edge.get_node("Clickable").on_press_down.connect(func(event): - var point = event.ray.get_collision_point() - point.y = 0 + var point=event.ray.get_collision_point() + point.y=0 add_corner(point, edge.get_index() + 1) ) - room.wall_edges.add_child(edge) room.wall_edges.move_child(edge, index) return edge @@ -277,4 +274,7 @@ func update_store(): store_room.corners = corners store_room.height = room.room_ceiling.position.y + # Manually update the array + Store.house.state.rooms = Store.house.state.rooms + Store.house.save_local() diff --git a/app/content/ui/menu/view/view_menu.gd b/app/content/ui/menu/view/view_menu.gd index d22a003..2fb3dd5 100644 --- a/app/content/ui/menu/view/view_menu.gd +++ b/app/content/ui/menu/view/view_menu.gd @@ -5,6 +5,9 @@ const Miniature = preload ("res://content/system/house/mini/miniature.gd") @onready var mini_view_button = $Content/MiniView @onready var heat_map_button = $Content/HeatMap @onready var humudity_map_button = $Content/HumidityMap +@onready var min_slider = $Content/MinSlider +@onready var max_slider = $Content/MaxSlider +@onready var opacity_slider = $Content/OpacitySlider @onready var background = $Background func _ready(): @@ -40,5 +43,51 @@ func _ready(): R.effect(func(_arg): heat_map_button.active=mini_view.heatmap_type.value == Miniature.HeatmapType.TEMPERATURE humudity_map_button.active=mini_view.heatmap_type.value == Miniature.HeatmapType.HUMIDITY - ) + + min_slider.on_value_changed.connect(func(value): + if value >= mini_view.selected_scale.value.y: + min_slider.value=mini_view.selected_scale.value.y + return + + mini_view.selected_scale.value.x=value + ) + + max_slider.on_value_changed.connect(func(value): + if value <= mini_view.selected_scale.value.x: + max_slider.value=mini_view.selected_scale.value.x + return + + mini_view.selected_scale.value.y=value + ) + + R.effect(func(_arg): + min_slider.value=mini_view.selected_scale.value.x + max_slider.value=mini_view.selected_scale.value.y + ) + + # Update Slider + R.effect(func(_arg): + var minmax=mini_view.get_base_scale() + min_slider.min=minmax.x + min_slider.max=minmax.y + + max_slider.min=minmax.x + max_slider.max=minmax.y + + var sensor_minmax=mini_view.get_sensor_scale() + + sensor_minmax.x=floor(sensor_minmax.x) + sensor_minmax.y=ceil(sensor_minmax.y) + + mini_view.selected_scale.value=sensor_minmax + min_slider.value=sensor_minmax.x + max_slider.value=sensor_minmax.y + + var unit=mini_view.get_sensor_unit() + + min_slider.label_unit=unit + max_slider.label_unit=unit + ) + + R.bind(opacity_slider, "value", mini_view.opacity, opacity_slider.on_value_changed) diff --git a/app/content/ui/menu/view/view_menu.tscn b/app/content/ui/menu/view/view_menu.tscn index a69710f..03cac72 100644 --- a/app/content/ui/menu/view/view_menu.tscn +++ b/app/content/ui/menu/view/view_menu.tscn @@ -1,8 +1,9 @@ -[gd_scene load_steps=5 format=3 uid="uid://ddpxthb414unp"] +[gd_scene load_steps=6 format=3 uid="uid://ddpxthb414unp"] [ext_resource type="Script" path="res://content/ui/menu/view/view_menu.gd" id="1_hxajx"] [ext_resource type="PackedScene" uid="uid://bsjqdvkt0u87c" path="res://content/ui/components/button/button.tscn" id="2_qan1b"] [ext_resource type="Material" uid="uid://bujy3egn1oqac" path="res://assets/materials/pri-500.material" id="2_se6ic"] +[ext_resource type="PackedScene" uid="uid://pk5k1q8bx0rj" path="res://content/ui/components/slider/slider.tscn" id="4_d3xhb"] [sub_resource type="BoxMesh" id="BoxMesh_qr3bi"] size = Vector3(0.3, 0.01, 0.3) @@ -58,3 +59,48 @@ text = "Humidity Map" font_size = 18 outline_size = 0 horizontal_alignment = 0 + +[node name="MinSlider" parent="Content" instance=ExtResource("4_d3xhb")] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0.06, 0.01, 0.2) +step = 1.0 +show_label = true +size = Vector3(10, 0.4, 1) + +[node name="MinValue" type="Label3D" parent="Content"] +transform = Transform3D(1, 0, 0, 0, 0, 1, 0, -1, 0, 0.15, 0.01, 0.2) +pixel_size = 0.001 +text = "Min Value" +font_size = 18 +outline_size = 0 +horizontal_alignment = 0 + +[node name="MaxSlider" parent="Content" instance=ExtResource("4_d3xhb")] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0.06, 0.01, 0.24) +step = 1.0 +show_label = true +size = Vector3(10, 0.4, 1) + +[node name="MaxValue" type="Label3D" parent="Content"] +transform = Transform3D(1, 0, 0, 0, 0, 1, 0, -1, 0, 0.15, 0.01, 0.24) +pixel_size = 0.001 +text = "Max Value" +font_size = 18 +outline_size = 0 +horizontal_alignment = 0 + +[node name="OpacitySlider" parent="Content" instance=ExtResource("4_d3xhb")] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0.06, 0.01, 0.28) +max = 100.0 +value = 30.0 +step = 10.0 +show_label = true +label_unit = "%" +size = Vector3(10, 0.4, 1) + +[node name="OpacityLabel" type="Label3D" parent="Content"] +transform = Transform3D(1, 0, 0, 0, 0, 1, 0, -1, 0, 0.15, 0.01, 0.28) +pixel_size = 0.001 +text = "Opacity" +font_size = 18 +outline_size = 0 +horizontal_alignment = 0 From caa73b5f55e9e997bc9dd5392de528b04e2eef31 Mon Sep 17 00:00:00 2001 From: Nitwel Date: Wed, 10 Apr 2024 16:52:23 +0200 Subject: [PATCH 10/10] clean up room collisions --- app/content/system/house/room/room.gd | 6 +++--- app/content/system/house/room/room.tscn | 6 +++++- app/content/system/house/room/states/view.gd | 16 ++++------------ app/content/ui/menu/room/views/rooms.gd | 4 ++-- app/lib/utils/mesh/construct_room_mesh.gd | 6 +++--- 5 files changed, 17 insertions(+), 21 deletions(-) diff --git a/app/content/system/house/room/room.gd b/app/content/system/house/room/room.gd index e9f1107..f2ed2f6 100644 --- a/app/content/system/house/room/room.gd +++ b/app/content/system/house/room/room.gd @@ -6,7 +6,7 @@ const ConstructRoomMesh = preload ("res://lib/utils/mesh/construct_room_mesh.gd" @onready var wall_edges = $Ceiling/WallEdges @onready var wall_mesh: MeshInstance3D = $WallMesh @onready var ceiling_mesh: MeshInstance3D = $CeilingMesh -@onready var wall_collisions = $WallCollisions +@onready var wall_collision = $WallCollision/CollisionShape3D @onready var room_floor = $Floor @onready var room_ceiling = $Ceiling @@ -60,9 +60,9 @@ static func generate_wall_mesh(room_store: Dictionary): var corners = room_store.corners var height = room_store.height - return ConstructRoomMesh.generate_wall_mesh_grid(corners, height) + return ConstructRoomMesh.generate_wall_mesh(corners, height) static func generate_ceiling_mesh(room_store: Dictionary): var corners = room_store.corners - return ConstructRoomMesh.generate_ceiling_mesh_grid(corners) + return ConstructRoomMesh.generate_ceiling_mesh(corners) diff --git a/app/content/system/house/room/room.tscn b/app/content/system/house/room/room.tscn index d222beb..e86326e 100644 --- a/app/content/system/house/room/room.tscn +++ b/app/content/system/house/room/room.tscn @@ -28,7 +28,11 @@ script = ExtResource("1_ugebq") [node name="CeilingMesh" type="MeshInstance3D" parent="."] -[node name="WallCollisions" type="Node3D" parent="."] +[node name="WallCollision" type="StaticBody3D" parent="."] +collision_layer = 24 +collision_mask = 0 + +[node name="CollisionShape3D" type="CollisionShape3D" parent="WallCollision"] [node name="Ceiling" type="StaticBody3D" parent="."] transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 2, 0) diff --git a/app/content/system/house/room/states/view.gd b/app/content/system/house/room/states/view.gd index e21c7ec..0bd1552 100644 --- a/app/content/system/house/room/states/view.gd +++ b/app/content/system/house/room/states/view.gd @@ -29,20 +29,12 @@ func _on_enter(): floor_shape.shape = room.ceiling_mesh.mesh.create_trimesh_shape() ceiling_shape.shape.backface_collision = true - var collision = CollisionShape3D.new() - collision.shape = room.wall_mesh.mesh.create_trimesh_shape() - - var static_body = StaticBody3D.new() - static_body.set_collision_layer_value(4, true) - static_body.set_collision_layer_value(5, true) - static_body.collision_mask = 0 - static_body.add_child(collision) - room.wall_collisions.add_child(static_body) + var wall_collisions = room.wall_mesh.mesh.create_trimesh_shape() + wall_collisions.backface_collision = true + room.wall_collision.shape = wall_collisions func _on_leave(): room.room_ceiling.get_node("CollisionShape3D").disabled = true room.room_floor.get_node("CollisionShape3D").disabled = true - for collision in room.wall_collisions.get_children(): - collision.queue_free() - await collision.tree_exited + room.wall_collision.shape = null diff --git a/app/content/ui/menu/room/views/rooms.gd b/app/content/ui/menu/room/views/rooms.gd index 967583f..803f87c 100644 --- a/app/content/ui/menu/room/views/rooms.gd +++ b/app/content/ui/menu/room/views/rooms.gd @@ -1,7 +1,7 @@ extends Node3D const Room = preload ("res://content/system/house/room/room.tscn") -const RoomType = preload ("res://content/system/house/room/room.gd") +const ConstructRoomMesh = preload ("res://lib/utils/mesh/construct_room_mesh.gd") const material_selected = preload ("../room_selected.tres") const material_unselected = preload ("../room_unselected.tres") @@ -128,7 +128,7 @@ func _generate_room_map(): current_max.y = max(current_max.y, corner.y) for room in rooms: - var mesh = RoomType.generate_ceiling_mesh(room) + var mesh = ConstructRoomMesh.generate_ceiling_mesh(room.corners) if mesh == null: continue diff --git a/app/lib/utils/mesh/construct_room_mesh.gd b/app/lib/utils/mesh/construct_room_mesh.gd index 92da23f..2ee9f5f 100644 --- a/app/lib/utils/mesh/construct_room_mesh.gd +++ b/app/lib/utils/mesh/construct_room_mesh.gd @@ -10,13 +10,13 @@ static func generate_wall_mesh(corners, height): for corner in corners: var corner3D = Vector3(corner.x, 0, corner.y) - st.add_vertex(corner3D) st.add_vertex(corner3D + wall_up) + st.add_vertex(corner3D) var first_corner = Vector3(corners[0].x, 0, corners[0].y) - st.add_vertex(first_corner) st.add_vertex(first_corner + wall_up) + st.add_vertex(first_corner) st.index() st.generate_normals() @@ -205,4 +205,4 @@ static func _create_mesh(points: PackedVector2Array, triangles: PackedInt32Array var mesh = st.commit() - return mesh \ No newline at end of file + return mesh