Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 21 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,26 @@
# Changelog

## 0.61.0-test4 — Every move on the beat

- Heads no longer turn, drift or circle on a clock of their own. Every head moves in steps on the beat: a step
lands on the kick and holds until the next one. Each passage picks a motion: scissors (odd and even cross),
a nod of the whole rig, a fan that opens and closes, a ladder that travels along and up, or a wave.
- Two beats a step, every beat in the second half of a peak; in a break a step a bar, growing with the build.
A clap nods the rig a little. Gobos turn with the tempo.
- A second place, Room (Settings → Show → Place): only the DJ and the booth in a closed 16 × 16 m room full of
light. A grid of beams in the ceiling, three rows of beams and spots on the wall behind the DJ, a row of floor
beams in front of the booth, beams on the wall ahead, on both side walls and in two corner towers, spots round
the ceiling, LED tubes floor to ceiling on every wall, rings and two LED frames round a screen on the wall
ahead, and LED bars along the foot of the walls. The same show plays it; cameras 3–5 stay inside the room.
- Beam rain is removed, and so are the dot grid on the far wall and the rings under the rear truss.
- A stage set in the main stage: two LED frames round the centre screen, six vertical LED tubes between the towers
in a V (tall at the outside) and a grid of LED rings on the back wall. The rings swell on the kick; per passage
the tubes rise, drop, pulse or alternate and the frames orbit, take turns or hit on the kick; in quiet moments
the tubes flash on the melody, in a break they fill with the build, and a drop lights the whole set.
- More rhythm in the light, in every genre: besides the chases the lead can fill up beat by beat, pump with the
kick, sparkle on the sixteenths, bounce between the edges and the middle, or split left and right. The supporting
groups pump with the kick under it (not with gentle strobes).

## 0.61.0-test3 — Rings, dots and beam rain

- LED rings under the rear truss and on the back towers: a full circle that swells on every kick.
Expand Down
2 changes: 1 addition & 1 deletion project.godot
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ config_version=5
[application]

config/name="Stage Visualizer"
config/version="0.61.0-test3"
config/version="0.61.0-test4"
run/main_scene="res://main.tscn"
config/features=PackedStringArray("4.7", "Forward Plus")

Expand Down
43 changes: 43 additions & 0 deletions scripts/hall.gd
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,13 @@ const BOOTH_Z := -33.0 # the front of the DJ table
const RISER := 0.4
const TABLE := DECK + RISER + 1.05
const BARRIER := -24.0
# The place: "hangar" (the festival hall) or "room" (only the DJ, in a closed room full of light).
static var venue := "hangar"
# The room: 16 × 16 m round the booth, its floor at the deck's height so the booth and the cameras stay put.
const ROOM_X := 8.0
const ROOM_Z0 := -42.4
const ROOM_Z1 := -26.4
const ROOM_TOP := DECK + 7.0

@export_enum("Two decks:2", "Festival — four decks:4") var booth_decks := 2
var screens: Array[ShaderMaterial] = []
Expand All @@ -29,6 +36,9 @@ var stage_screen_material: ShaderMaterial

func build() -> void:
var black := Kit.mat(Color(0.018, 0.018, 0.02), 0.8)
if venue == "room":
_room(black)
return
var frame := _hall_material(Color(0.17, 0.20, 0.19), 0.73, 0.12, 0.3)
var boxes := Kit.Batch.new(Kit.unit_box(), frame)
var dark := Kit.Batch.new(Kit.unit_box(), black)
Expand Down Expand Up @@ -79,8 +89,35 @@ func build() -> void:
boxes.build(self)
dark.build(self)

# A closed room: dark concrete floor, walls and ceiling that take the colour of the light, the booth in the middle,
# a screen on the wall in front of the DJ, and haze that fills it.
func _room(black: Material) -> void:
var size := Vector3(ROOM_X * 2.0, ROOM_TOP - DECK, ROOM_Z1 - ROOM_Z0)
var middle := Vector3(0.0, DECK, (ROOM_Z0 + ROOM_Z1) / 2.0)
var floor_mesh := MeshInstance3D.new()
var plane := PlaneMesh.new()
plane.size = Vector2(size.x, size.z)
floor_mesh.mesh = plane
floor_mesh.material_override = _concrete()
floor_mesh.position = middle + Vector3(0.0, 0.001, 0.0)
add_child(floor_mesh)
var walls := Kit.Batch.new(Kit.unit_box(), _hall_material(Color(0.07, 0.07, 0.075), 0.9, 0.0, 0.45))
walls.add(Kit.block(Vector3(size.x, DECK, size.z), middle - Vector3(0.0, DECK / 2.0, 0.0))) # the slab under the floor
walls.add(Kit.block(Vector3(size.x + 0.6, 0.3, size.z + 0.6), middle + Vector3(0.0, size.y + 0.15, 0.0)))
for side in [-1.0, 1.0]:
walls.add(Kit.block(Vector3(0.3, size.y, size.z), middle + Vector3(side * (ROOM_X + 0.15), size.y / 2.0, 0.0)))
walls.add(Kit.block(Vector3(size.x, size.y, 0.3), middle + Vector3(0.0, size.y / 2.0, side * (size.z / 2.0 + 0.15))))
walls.build(self).name = "RoomWalls"
var dark := Kit.Batch.new(Kit.unit_box(), black)
dark.add(Kit.block(Vector3(6, RISER, 3.2), Vector3(0, DECK + RISER / 2, BOOTH_Z - 0.6)))
dark.build(self)
_stage_screen()
_booth(black)
_fog("RoomHaze", middle + Vector3(0.0, size.y / 2.0, 0.0), size - Vector3(0.4, 0.4, 0.4), 0.016)

func _stage_screen() -> void:
var center := Vector3(0, DECK + 2.8 + 3.5, -36.3)
if venue == "room": center = Vector3(0, DECK + 3.6, ROOM_Z1 - 0.12)
var frame := Kit.mat(Color(0.012, 0.012, 0.014), 0.8)
stage_screen = Node3D.new()
stage_screen.name = "StageScreen"
Expand All @@ -95,6 +132,12 @@ func _stage_screen() -> void:
face.material_override = stage_screen_material
face.position = center
stage_screen.add_child(face)
if venue == "room":
# on the wall in front of the DJ, smaller, turned to face the booth
for child in stage_screen.get_children():
child.position = center + (child.position - center) * Vector3(0.55, 0.55, -0.55) # its frame behind it
child.scale = Vector3(0.55, 0.55, 0.55)
child.rotation.y = PI

# Two floor hazers at the rear, with recessed outlets facing the crowd.
func _hazers(boxes: Kit.Batch, dark: Kit.Batch) -> void:
Expand Down
7 changes: 6 additions & 1 deletion scripts/main.gd
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,7 @@ func _ready() -> void:
if args.has("seed"): seed(int(args.seed))
for n in ["sv_beat", "sv_energy", "sv_hands", "sv_haze", "sv_phones"]:
RenderingServer.global_shader_parameter_add(n, RenderingServer.GLOBAL_VAR_TYPE_FLOAT, 1.0 if n == "sv_haze" else 0.0)
Hall.venue = str(args.get("venue", settings.values.get("venue", "hangar")))
hall = Hall.new()
add_child(hall)
hall.build()
Expand All @@ -106,7 +107,7 @@ func _ready() -> void:
rig.build()
crowd = Crowd.new()
add_child(crowd)
crowd.build(3000)
crowd.build(0 if Hall.venue == "room" else 3000) # the room has no crowd: only the DJ
_environment()
view = View.new()
add_child(view)
Expand Down Expand Up @@ -282,6 +283,10 @@ func _hud() -> void:

# The source and the graphics, from the settings screen (and once at the start).
func _apply_settings(options: Dictionary) -> void:
# another place is another build: the scene loads again, in the new place
if str(options.get("venue", Hall.venue)) != Hall.venue and not args.has("venue"):
get_tree().call_deferred("reload_current_scene")
return
if hall.stage_screen: hall.stage_screen.visible = bool(options.get("stage_screen", true))
show.genre = options.get("genre", show.genre)
show.safe = args.has("safe") or bool(options.get("safe", show.safe))
Expand Down
Loading
Loading