|
|
|
@@ -3,17 +3,37 @@ extends RefCounted
|
|
|
|
|
## World-aligned, bounded vector motifs for finite walls and Ground.
|
|
|
|
|
|
|
|
|
|
const WALL_FINISHES: Array[StringName] = [&"finish_wall_paint", &"finish_wall_brick", &"finish_wall_wood"]
|
|
|
|
|
const BACKGROUND_FINISHES: Array[StringName] = [&"finish_background_grass", &"finish_background_concrete", &"finish_background_carpet"]
|
|
|
|
|
const GROUND_FINISHES: Array[StringName] = [&"finish_ground_paint", &"finish_ground_brick", &"finish_ground_wood", &"finish_ground_grass", &"finish_ground_dirt", &"finish_ground_sidewalk", &"finish_ground_asphalt"]
|
|
|
|
|
const MAX_CELLS: int = 1200
|
|
|
|
|
const BRICK_WIDTH: float = 82.0
|
|
|
|
|
const BRICK_HEIGHT: float = 34.0
|
|
|
|
|
const MAX_VISIBLE_BRICK_CELLS: int = 12000
|
|
|
|
|
const WALL_BRICK_WIDTH: float = 100.0
|
|
|
|
|
const WALL_BRICK_HEIGHT: float = 38.0
|
|
|
|
|
const MAX_WALL_BRICK_CELLS: int = 1200
|
|
|
|
|
const MAX_BACKGROUND_CELLS: int = 12000
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static func is_wall_finish(id: StringName) -> bool:
|
|
|
|
|
return WALL_FINISHES.has(id)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static func is_background_finish(id: StringName) -> bool:
|
|
|
|
|
return BACKGROUND_FINISHES.has(id)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static func default_tint(finish: StringName) -> Color:
|
|
|
|
|
match finish:
|
|
|
|
|
&"finish_wall_paint": return Color("#5A9D70")
|
|
|
|
|
&"finish_wall_brick": return Color("#B95F3D")
|
|
|
|
|
&"finish_wall_wood": return Color("#C87137")
|
|
|
|
|
&"finish_background_grass": return Color("#72A84C")
|
|
|
|
|
&"finish_background_concrete": return Color("#A6AAA3")
|
|
|
|
|
&"finish_background_carpet": return Color("#8B537B")
|
|
|
|
|
_: return Color("#5A9D70")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static func is_ground_finish(id: StringName) -> bool:
|
|
|
|
|
return GROUND_FINISHES.has(id) or id == &"finish_ground_legacy"
|
|
|
|
|
|
|
|
|
@@ -24,9 +44,10 @@ static func draw_wall(
|
|
|
|
|
finish: StringName,
|
|
|
|
|
tint: Color,
|
|
|
|
|
world_origin: Vector2,
|
|
|
|
|
drawing_scale: Vector2 = Vector2.ONE
|
|
|
|
|
drawing_scale: Vector2 = Vector2.ONE,
|
|
|
|
|
cull_to_viewport: bool = true
|
|
|
|
|
) -> void:
|
|
|
|
|
_draw_surface(canvas, rect, finish, tint, world_origin, drawing_scale, true)
|
|
|
|
|
_draw_surface(canvas, rect, finish, tint, world_origin, drawing_scale, true, false, cull_to_viewport)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static func draw_ground(
|
|
|
|
@@ -37,7 +58,19 @@ static func draw_ground(
|
|
|
|
|
world_origin: Vector2,
|
|
|
|
|
drawing_scale: Vector2 = Vector2.ONE
|
|
|
|
|
) -> void:
|
|
|
|
|
_draw_surface(canvas, rect, finish, tint, world_origin, drawing_scale, false)
|
|
|
|
|
_draw_surface(canvas, rect, finish, tint, world_origin, drawing_scale, false, false, true)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static func draw_background(
|
|
|
|
|
canvas: CanvasItem,
|
|
|
|
|
rect: Rect2,
|
|
|
|
|
finish: StringName,
|
|
|
|
|
tint: Color,
|
|
|
|
|
world_origin: Vector2,
|
|
|
|
|
drawing_scale: Vector2 = Vector2.ONE,
|
|
|
|
|
cull_to_viewport: bool = true
|
|
|
|
|
) -> void:
|
|
|
|
|
_draw_surface(canvas, rect, finish, tint, world_origin, drawing_scale, false, true, cull_to_viewport)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static func _draw_surface(
|
|
|
|
@@ -47,7 +80,9 @@ static func _draw_surface(
|
|
|
|
|
tint: Color,
|
|
|
|
|
world_origin: Vector2,
|
|
|
|
|
drawing_scale: Vector2,
|
|
|
|
|
wall: bool
|
|
|
|
|
wall: bool,
|
|
|
|
|
background: bool,
|
|
|
|
|
cull_to_viewport: bool
|
|
|
|
|
) -> void:
|
|
|
|
|
var normalized := rect.abs()
|
|
|
|
|
if normalized.size.x <= 0.0 or normalized.size.y <= 0.0:
|
|
|
|
@@ -57,11 +92,15 @@ static func _draw_surface(
|
|
|
|
|
if finish == &"finish_ground_legacy":
|
|
|
|
|
base = Color("#468B42")
|
|
|
|
|
elif finish.ends_with("brick"):
|
|
|
|
|
base = Color("#B95F3D") if wall else Color("#994D35")
|
|
|
|
|
base = Color("#D2CBAF") if wall else Color("#994D35")
|
|
|
|
|
elif finish.ends_with("wood"):
|
|
|
|
|
base = Color("#9A673C") if wall else Color("#B88951")
|
|
|
|
|
elif finish == &"finish_ground_grass":
|
|
|
|
|
elif finish == &"finish_ground_grass" or finish == &"finish_background_grass":
|
|
|
|
|
base = Color("#72A84C")
|
|
|
|
|
elif finish == &"finish_background_concrete":
|
|
|
|
|
base = Color("#A6AAA3")
|
|
|
|
|
elif finish == &"finish_background_carpet":
|
|
|
|
|
base = tint
|
|
|
|
|
elif finish == &"finish_ground_dirt":
|
|
|
|
|
base = Color("#8E633E")
|
|
|
|
|
elif finish == &"finish_ground_sidewalk":
|
|
|
|
@@ -70,13 +109,39 @@ static func _draw_surface(
|
|
|
|
|
base = Color("#505A62")
|
|
|
|
|
canvas.draw_rect(normalized, base, true)
|
|
|
|
|
if finish.ends_with("brick"):
|
|
|
|
|
var view_rect: Rect2 = _visible_local_rect(canvas)
|
|
|
|
|
var view_rect: Rect2 = _visible_local_rect(canvas) if cull_to_viewport else normalized
|
|
|
|
|
var pattern_rect: Rect2 = normalized.intersection(view_rect) if not view_rect.size.is_zero_approx() else normalized
|
|
|
|
|
if pattern_rect.size.x > 0.0 and pattern_rect.size.y > 0.0:
|
|
|
|
|
var detail_scale: float = brick_detail_scale_for_view(view_rect.size if not view_rect.size.is_zero_approx() else normalized.size, motif_scale)
|
|
|
|
|
_draw_bricks(canvas, pattern_rect, world_origin, base, motif_scale, detail_scale)
|
|
|
|
|
var detail_size: Vector2 = view_rect.size if not view_rect.size.is_zero_approx() else normalized.size
|
|
|
|
|
var detail_scale: float = brick_detail_scale_for_view(detail_size, motif_scale, wall)
|
|
|
|
|
if wall:
|
|
|
|
|
_draw_wall_bricks(canvas, pattern_rect, world_origin, motif_scale, detail_scale, tint)
|
|
|
|
|
else:
|
|
|
|
|
_draw_bricks(canvas, pattern_rect, world_origin, base, motif_scale, detail_scale)
|
|
|
|
|
elif finish.ends_with("wood"):
|
|
|
|
|
_draw_wood(canvas, normalized, world_origin, base, motif_scale)
|
|
|
|
|
if wall:
|
|
|
|
|
var view_rect: Rect2 = _visible_local_rect(canvas) if cull_to_viewport else normalized
|
|
|
|
|
var pattern_rect: Rect2 = normalized.intersection(view_rect) if not view_rect.size.is_zero_approx() else normalized
|
|
|
|
|
if pattern_rect.size.x > 0.0 and pattern_rect.size.y > 0.0:
|
|
|
|
|
var detail_scale: float = wood_detail_scale_for_view(pattern_rect.size, motif_scale)
|
|
|
|
|
_draw_wall_wood(canvas, pattern_rect, world_origin, motif_scale, detail_scale, tint)
|
|
|
|
|
else:
|
|
|
|
|
_draw_wood(canvas, normalized, world_origin, base, motif_scale)
|
|
|
|
|
elif finish == &"finish_background_grass":
|
|
|
|
|
var view_rect: Rect2 = _visible_local_rect(canvas) if cull_to_viewport else normalized
|
|
|
|
|
var pattern_rect: Rect2 = normalized.intersection(view_rect) if not view_rect.size.is_zero_approx() else normalized
|
|
|
|
|
if pattern_rect.size.x > 0.0 and pattern_rect.size.y > 0.0:
|
|
|
|
|
_draw_background_grass(canvas, pattern_rect, world_origin, motif_scale)
|
|
|
|
|
elif finish == &"finish_background_concrete":
|
|
|
|
|
var view_rect: Rect2 = _visible_local_rect(canvas) if cull_to_viewport else normalized
|
|
|
|
|
var pattern_rect: Rect2 = normalized.intersection(view_rect) if not view_rect.size.is_zero_approx() else normalized
|
|
|
|
|
if pattern_rect.size.x > 0.0 and pattern_rect.size.y > 0.0:
|
|
|
|
|
_draw_background_concrete(canvas, pattern_rect, world_origin, motif_scale)
|
|
|
|
|
elif finish == &"finish_background_carpet":
|
|
|
|
|
var view_rect: Rect2 = _visible_local_rect(canvas) if cull_to_viewport else normalized
|
|
|
|
|
var pattern_rect: Rect2 = normalized.intersection(view_rect) if not view_rect.size.is_zero_approx() else normalized
|
|
|
|
|
if pattern_rect.size.x > 0.0 and pattern_rect.size.y > 0.0:
|
|
|
|
|
_draw_background_carpet(canvas, pattern_rect, world_origin, motif_scale, tint)
|
|
|
|
|
elif finish == &"finish_ground_grass":
|
|
|
|
|
_draw_grass(canvas, normalized, world_origin, motif_scale)
|
|
|
|
|
elif finish == &"finish_ground_dirt":
|
|
|
|
@@ -89,20 +154,529 @@ static func _draw_surface(
|
|
|
|
|
push_warning("StageSurfaceRenderer: unknown finish '%s'; drawing paint." % String(finish))
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static func brick_detail_scale_for_view(view_size: Vector2, motif_scale: Vector2 = Vector2.ONE) -> float:
|
|
|
|
|
static func brick_detail_scale_for_view(view_size: Vector2, motif_scale: Vector2 = Vector2.ONE, wall: bool = false) -> float:
|
|
|
|
|
var scale: float = 1.0
|
|
|
|
|
var safe_size: Vector2 = Vector2(maxf(1.0, view_size.x), maxf(1.0, view_size.y))
|
|
|
|
|
var safe_motif_scale: Vector2 = _normalized_scale(motif_scale)
|
|
|
|
|
var brick_width: float = WALL_BRICK_WIDTH if wall else BRICK_WIDTH
|
|
|
|
|
var brick_height: float = WALL_BRICK_HEIGHT if wall else BRICK_HEIGHT
|
|
|
|
|
var max_cells: int = MAX_WALL_BRICK_CELLS if wall else MAX_VISIBLE_BRICK_CELLS
|
|
|
|
|
for _iteration: int in 8:
|
|
|
|
|
var columns: int = int(ceil(safe_size.x * safe_motif_scale.x / (brick_width * scale))) + 2
|
|
|
|
|
var rows: int = int(ceil(safe_size.y * safe_motif_scale.y / (brick_height * scale))) + 2
|
|
|
|
|
var cell_count: int = rows * columns
|
|
|
|
|
if cell_count <= max_cells:
|
|
|
|
|
return scale
|
|
|
|
|
scale *= sqrt(float(cell_count) / float(max_cells)) * 1.01
|
|
|
|
|
return scale
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static func wood_detail_scale_for_view(view_size: Vector2, motif_scale: Vector2 = Vector2.ONE) -> float:
|
|
|
|
|
var scale: float = 1.0
|
|
|
|
|
var safe_size: Vector2 = Vector2(maxf(1.0, view_size.x), maxf(1.0, view_size.y))
|
|
|
|
|
var safe_motif_scale: Vector2 = _normalized_scale(motif_scale)
|
|
|
|
|
for _iteration: int in 8:
|
|
|
|
|
var columns: int = int(ceil(safe_size.x * safe_motif_scale.x / (BRICK_WIDTH * scale))) + 2
|
|
|
|
|
var rows: int = int(ceil(safe_size.y * safe_motif_scale.y / (BRICK_HEIGHT * scale))) + 2
|
|
|
|
|
var columns: int = int(ceil(safe_size.x * safe_motif_scale.x / (320.0 * scale))) + 2
|
|
|
|
|
var rows: int = int(ceil(safe_size.y * safe_motif_scale.y / (64.0 * scale))) + 2
|
|
|
|
|
var cell_count: int = rows * columns
|
|
|
|
|
if cell_count <= MAX_VISIBLE_BRICK_CELLS:
|
|
|
|
|
if cell_count <= MAX_CELLS:
|
|
|
|
|
return scale
|
|
|
|
|
scale *= sqrt(float(cell_count) / float(MAX_VISIBLE_BRICK_CELLS)) * 1.01
|
|
|
|
|
scale *= sqrt(float(cell_count) / float(MAX_CELLS)) * 1.01
|
|
|
|
|
return scale
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static func _draw_wall_wood(canvas: CanvasItem, rect: Rect2, origin: Vector2, motif_scale: Vector2, detail_scale: float, tint: Color) -> void:
|
|
|
|
|
const BOARD_HEIGHT: float = 64.0
|
|
|
|
|
const PLANK_WIDTH: float = 320.0
|
|
|
|
|
var safe_scale: Vector2 = _normalized_scale(motif_scale)
|
|
|
|
|
var board_world_height: float = BOARD_HEIGHT * detail_scale
|
|
|
|
|
var plank_world_width: float = PLANK_WIDTH * detail_scale
|
|
|
|
|
var world_left: float = rect.position.x * safe_scale.x + origin.x
|
|
|
|
|
var world_right: float = rect.end.x * safe_scale.x + origin.x
|
|
|
|
|
var world_top: float = rect.position.y * safe_scale.y + origin.y
|
|
|
|
|
var world_bottom: float = rect.end.y * safe_scale.y + origin.y
|
|
|
|
|
var first_row: int = floori(world_top / board_world_height)
|
|
|
|
|
var last_row: int = floori((world_bottom - 0.001) / board_world_height)
|
|
|
|
|
var row_count: int = mini(last_row - first_row + 1, MAX_CELLS)
|
|
|
|
|
var natural: Color = default_tint(&"finish_wall_wood")
|
|
|
|
|
var seam_color: Color = _material_color(Color("#784421"), tint, natural)
|
|
|
|
|
var grain_color: Color = _material_color(Color("#A05A2C"), tint, natural)
|
|
|
|
|
var highlight_color: Color = _material_color(Color("#E39A59"), tint, natural)
|
|
|
|
|
for row_offset: int in row_count:
|
|
|
|
|
var row: int = first_row + row_offset
|
|
|
|
|
var board_world_top: float = float(row) * board_world_height
|
|
|
|
|
var board_local_top: float = (board_world_top - origin.y) / safe_scale.y
|
|
|
|
|
var stagger: float = plank_world_width * 0.5 if posmod(row, 2) == 1 else 0.0
|
|
|
|
|
var first_column: int = floori((world_left - stagger) / plank_world_width)
|
|
|
|
|
var last_column: int = floori((world_right - stagger - 0.001) / plank_world_width)
|
|
|
|
|
var column_count: int = mini(last_column - first_column + 1, MAX_CELLS)
|
|
|
|
|
for column_offset: int in column_count:
|
|
|
|
|
var column: int = first_column + column_offset
|
|
|
|
|
var plank_world_left: float = float(column) * plank_world_width + stagger
|
|
|
|
|
var plank_rect := Rect2(
|
|
|
|
|
Vector2((plank_world_left - origin.x) / safe_scale.x, board_local_top),
|
|
|
|
|
Vector2(plank_world_width / safe_scale.x, board_world_height / safe_scale.y)
|
|
|
|
|
)
|
|
|
|
|
var visible_plank: Rect2 = rect.intersection(plank_rect)
|
|
|
|
|
if visible_plank.size.x <= 0.0 or visible_plank.size.y <= 0.0:
|
|
|
|
|
continue
|
|
|
|
|
var tone_index: int = posmod(row + column, 3)
|
|
|
|
|
var plank_color: Color = _material_color(Color("#C87137"), tint, natural)
|
|
|
|
|
if tone_index == 1:
|
|
|
|
|
plank_color = plank_color.darkened(0.045)
|
|
|
|
|
elif tone_index == 2:
|
|
|
|
|
plank_color = plank_color.lightened(0.035)
|
|
|
|
|
canvas.draw_rect(visible_plank, plank_color, true)
|
|
|
|
|
var plank_local_left: float = (plank_world_left - origin.x) / safe_scale.x
|
|
|
|
|
_draw_clipped_line(
|
|
|
|
|
canvas, rect,
|
|
|
|
|
Vector2(plank_local_left, board_local_top),
|
|
|
|
|
Vector2(plank_local_left, board_local_top + board_world_height / safe_scale.y),
|
|
|
|
|
_color_with_alpha(seam_color, 0.88), 2.0 / safe_scale.x
|
|
|
|
|
)
|
|
|
|
|
_draw_wall_wood_grain(
|
|
|
|
|
canvas, rect, plank_world_left, board_world_top, plank_world_width, board_world_height,
|
|
|
|
|
origin, safe_scale, row, column, grain_color, highlight_color, detail_scale, tint, natural
|
|
|
|
|
)
|
|
|
|
|
_draw_wall_wood_knot(
|
|
|
|
|
canvas, rect, plank_world_left, board_world_top, plank_world_width, board_world_height,
|
|
|
|
|
origin, safe_scale, row, column, detail_scale, tint, natural
|
|
|
|
|
)
|
|
|
|
|
_draw_clipped_line(
|
|
|
|
|
canvas, rect,
|
|
|
|
|
Vector2(rect.position.x, board_local_top), Vector2(rect.end.x, board_local_top),
|
|
|
|
|
seam_color, 2.4 / safe_scale.y
|
|
|
|
|
)
|
|
|
|
|
_draw_clipped_line(
|
|
|
|
|
canvas, rect,
|
|
|
|
|
Vector2(rect.position.x, board_local_top + 2.4 / safe_scale.y),
|
|
|
|
|
Vector2(rect.end.x, board_local_top + 2.4 / safe_scale.y),
|
|
|
|
|
_color_with_alpha(highlight_color, 0.62), 1.0 / safe_scale.y
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static func _draw_wall_wood_grain(
|
|
|
|
|
canvas: CanvasItem,
|
|
|
|
|
clip_rect: Rect2,
|
|
|
|
|
plank_world_left: float,
|
|
|
|
|
board_world_top: float,
|
|
|
|
|
plank_world_width: float,
|
|
|
|
|
board_world_height: float,
|
|
|
|
|
origin: Vector2,
|
|
|
|
|
motif_scale: Vector2,
|
|
|
|
|
row: int,
|
|
|
|
|
column: int,
|
|
|
|
|
grain_color: Color,
|
|
|
|
|
highlight_color: Color,
|
|
|
|
|
detail_scale: float,
|
|
|
|
|
tint: Color,
|
|
|
|
|
natural: Color
|
|
|
|
|
) -> void:
|
|
|
|
|
const TRACK_COUNT: int = 5
|
|
|
|
|
const SAMPLES: int = 32
|
|
|
|
|
var seed: int = row * 73856093 + column * 19349663
|
|
|
|
|
for track: int in TRACK_COUNT:
|
|
|
|
|
var track_seed: int = seed + track * 83492791
|
|
|
|
|
var lane: float = 0.16 + _wood_hash(track_seed) * 0.68
|
|
|
|
|
var amplitude: float = (0.55 + _wood_hash(track_seed + 11) * 2.4) * detail_scale
|
|
|
|
|
var cycles: float = 1.0 + _wood_hash(track_seed + 23) * 2.6
|
|
|
|
|
var phase: float = _wood_hash(track_seed + 37) * TAU
|
|
|
|
|
var points := PackedVector2Array()
|
|
|
|
|
for sample: int in SAMPLES + 1:
|
|
|
|
|
var t: float = float(sample) / float(SAMPLES)
|
|
|
|
|
var wave: float = sin(t * TAU * cycles + phase) * amplitude
|
|
|
|
|
wave += sin(t * TAU * (cycles * 0.43 + 0.4) + phase * 1.7) * amplitude * 0.32
|
|
|
|
|
var world_x: float = plank_world_left + t * plank_world_width
|
|
|
|
|
var world_y: float = board_world_top + lane * board_world_height + wave
|
|
|
|
|
points.append(Vector2((world_x - origin.x) / motif_scale.x, (world_y - origin.y) / motif_scale.y))
|
|
|
|
|
_draw_clipped_polyline(canvas, clip_rect, points, _color_with_alpha(grain_color, 0.19), 5.0 * detail_scale / motif_scale.y)
|
|
|
|
|
_draw_clipped_polyline(canvas, clip_rect, points, _color_with_alpha(grain_color, 0.58), 1.15 * detail_scale / motif_scale.y)
|
|
|
|
|
var highlight_points := PackedVector2Array()
|
|
|
|
|
for point: Vector2 in points:
|
|
|
|
|
highlight_points.append(point + Vector2(0.0, -1.0 * detail_scale / motif_scale.y))
|
|
|
|
|
_draw_clipped_polyline(canvas, clip_rect, highlight_points, _color_with_alpha(highlight_color, 0.32), 0.9 * detail_scale / motif_scale.y)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static func _draw_wall_wood_knot(
|
|
|
|
|
canvas: CanvasItem,
|
|
|
|
|
clip_rect: Rect2,
|
|
|
|
|
plank_world_left: float,
|
|
|
|
|
board_world_top: float,
|
|
|
|
|
plank_world_width: float,
|
|
|
|
|
board_world_height: float,
|
|
|
|
|
origin: Vector2,
|
|
|
|
|
motif_scale: Vector2,
|
|
|
|
|
row: int,
|
|
|
|
|
column: int,
|
|
|
|
|
detail_scale: float,
|
|
|
|
|
tint: Color,
|
|
|
|
|
natural: Color
|
|
|
|
|
) -> void:
|
|
|
|
|
var seed: int = row * 92821 + column * 68917 + 31
|
|
|
|
|
if _wood_hash(seed) > 0.24:
|
|
|
|
|
return
|
|
|
|
|
var center_world := Vector2(
|
|
|
|
|
plank_world_left + plank_world_width * (0.27 + _wood_hash(seed + 1) * 0.46),
|
|
|
|
|
board_world_top + board_world_height * (0.34 + _wood_hash(seed + 2) * 0.34)
|
|
|
|
|
)
|
|
|
|
|
var radius_x: float = (12.0 + _wood_hash(seed + 3) * 12.0) * detail_scale
|
|
|
|
|
var radius_y: float = (3.0 + _wood_hash(seed + 4) * 2.8) * detail_scale
|
|
|
|
|
var center := Vector2((center_world.x - origin.x) / motif_scale.x, (center_world.y - origin.y) / motif_scale.y)
|
|
|
|
|
for ring: int in 3:
|
|
|
|
|
var ring_scale: float = 1.0 - float(ring) * 0.27
|
|
|
|
|
var points := PackedVector2Array()
|
|
|
|
|
for point_index: int in 33:
|
|
|
|
|
var angle: float = TAU * float(point_index) / 32.0
|
|
|
|
|
var wobble: float = 1.0 + 0.07 * sin(angle * 3.0 + float(seed % 17))
|
|
|
|
|
var world_offset := Vector2(
|
|
|
|
|
cos(angle) * radius_x * ring_scale * wobble,
|
|
|
|
|
sin(angle) * radius_y * ring_scale * (1.0 + 0.08 * cos(angle * 2.0))
|
|
|
|
|
)
|
|
|
|
|
points.append(center + Vector2(world_offset.x / motif_scale.x, world_offset.y / motif_scale.y))
|
|
|
|
|
var ring_source: Color = Color("#784421") if ring != 1 else Color("#E39A59")
|
|
|
|
|
var ring_color: Color = _color_with_alpha(_material_color(ring_source, tint, natural), 0.56 if ring != 1 else 0.52)
|
|
|
|
|
var ring_width: float = (1.25 if ring != 1 else 0.85) * detail_scale / motif_scale.y
|
|
|
|
|
_draw_clipped_polyline(canvas, clip_rect, points, ring_color, ring_width)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static func _draw_clipped_polyline(canvas: CanvasItem, rect: Rect2, points: PackedVector2Array, color: Color, width: float) -> void:
|
|
|
|
|
if points.size() < 2:
|
|
|
|
|
return
|
|
|
|
|
var inset: float = maxf(0.0, width) * 0.5
|
|
|
|
|
var safe_rect := Rect2(rect.position + Vector2.ONE * inset, rect.size - Vector2.ONE * inset * 2.0)
|
|
|
|
|
var fully_inside: bool = safe_rect.size.x > 0.0 and safe_rect.size.y > 0.0
|
|
|
|
|
if fully_inside:
|
|
|
|
|
for point: Vector2 in points:
|
|
|
|
|
if not safe_rect.has_point(point):
|
|
|
|
|
fully_inside = false
|
|
|
|
|
break
|
|
|
|
|
if fully_inside:
|
|
|
|
|
canvas.draw_polyline(points, color, width, true)
|
|
|
|
|
return
|
|
|
|
|
for index: int in range(points.size() - 1):
|
|
|
|
|
_draw_clipped_line(canvas, rect, points[index], points[index + 1], color, width)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static func _wood_hash(seed: int) -> float:
|
|
|
|
|
var value: float = sin(float(seed) * 12.9898 + 78.233) * 43758.5453
|
|
|
|
|
return value - floorf(value)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static func _color_with_alpha(color: Color, alpha: float) -> Color:
|
|
|
|
|
return Color(color.r, color.g, color.b, alpha)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static func _material_color(source: Color, selected: Color, natural: Color) -> Color:
|
|
|
|
|
var natural_value: float = maxf(0.08, natural.v)
|
|
|
|
|
var source_value_ratio: float = source.v / natural_value
|
|
|
|
|
var value: float = clampf(selected.v * source_value_ratio, 0.035, 1.0)
|
|
|
|
|
var natural_saturation: float = maxf(0.08, natural.s)
|
|
|
|
|
var source_saturation_ratio: float = source.s / natural_saturation
|
|
|
|
|
var saturation: float = clampf(selected.s * source_saturation_ratio, 0.0, 1.0)
|
|
|
|
|
return Color.from_hsv(selected.h, saturation, value, source.a)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static func _draw_background_grass(canvas: CanvasItem, rect: Rect2, origin: Vector2, motif_scale: Vector2) -> void:
|
|
|
|
|
const CELL_WIDTH: float = 44.0
|
|
|
|
|
const CELL_HEIGHT: float = 36.0
|
|
|
|
|
var world_left: float = rect.position.x * motif_scale.x + origin.x
|
|
|
|
|
var world_right: float = rect.end.x * motif_scale.x + origin.x
|
|
|
|
|
var world_top: float = rect.position.y * motif_scale.y + origin.y
|
|
|
|
|
var world_bottom: float = rect.end.y * motif_scale.y + origin.y
|
|
|
|
|
var first_column: int = floori(world_left / CELL_WIDTH) - 1
|
|
|
|
|
var last_column: int = floori(world_right / CELL_WIDTH) + 1
|
|
|
|
|
var first_row: int = floori(world_top / CELL_HEIGHT) - 1
|
|
|
|
|
var last_row: int = floori(world_bottom / CELL_HEIGHT) + 1
|
|
|
|
|
var remaining: int = MAX_BACKGROUND_CELLS
|
|
|
|
|
for row: int in range(first_row, last_row + 1):
|
|
|
|
|
for column: int in range(first_column, last_column + 1):
|
|
|
|
|
if remaining <= 0:
|
|
|
|
|
return
|
|
|
|
|
remaining -= 1
|
|
|
|
|
var seed: int = row * 73856093 + column * 19349663 + 197
|
|
|
|
|
var center_world := Vector2((float(column) + 0.5) * CELL_WIDTH, (float(row) + 0.5) * CELL_HEIGHT)
|
|
|
|
|
center_world += Vector2((_wood_hash(seed) - 0.5) * 34.0, (_wood_hash(seed + 1) - 0.5) * 26.0)
|
|
|
|
|
var center := Vector2((center_world.x - origin.x) / motif_scale.x, (center_world.y - origin.y) / motif_scale.y)
|
|
|
|
|
if not rect.grow(8.0).has_point(center):
|
|
|
|
|
continue
|
|
|
|
|
var tuft_color: Color = Color("#3A7837").lightened(_wood_hash(seed + 2) * 0.24)
|
|
|
|
|
var highlight: Color = Color("#C3DA74").darkened(_wood_hash(seed + 3) * 0.24)
|
|
|
|
|
var radius: float = 1.8 + _wood_hash(seed + 4) * 1.6
|
|
|
|
|
canvas.draw_circle(center, radius, _color_with_alpha(tuft_color, 0.56))
|
|
|
|
|
for blade: int in 4:
|
|
|
|
|
var blade_seed: int = seed + blade * 47 + 11
|
|
|
|
|
var x_offset: float = (_wood_hash(blade_seed) - 0.5) * 9.0 / motif_scale.x
|
|
|
|
|
var y_offset: float = (_wood_hash(blade_seed + 1) - 0.5) * 7.0 / motif_scale.y
|
|
|
|
|
var blade_height: float = (4.5 + _wood_hash(blade_seed + 2) * 4.0) / motif_scale.y
|
|
|
|
|
var start := center + Vector2(x_offset, y_offset)
|
|
|
|
|
var tip := start + Vector2((_wood_hash(blade_seed + 3) - 0.5) * 4.0 / motif_scale.x, -blade_height)
|
|
|
|
|
_draw_clipped_line(canvas, rect, start, tip, _color_with_alpha(highlight, 0.78), 1.25 / motif_scale.y)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static func _draw_background_concrete(canvas: CanvasItem, rect: Rect2, origin: Vector2, motif_scale: Vector2) -> void:
|
|
|
|
|
const SLAB_WIDTH: float = 280.0
|
|
|
|
|
const SLAB_HEIGHT: float = 190.0
|
|
|
|
|
var world_left: float = rect.position.x * motif_scale.x + origin.x
|
|
|
|
|
var world_right: float = rect.end.x * motif_scale.x + origin.x
|
|
|
|
|
var world_top: float = rect.position.y * motif_scale.y + origin.y
|
|
|
|
|
var world_bottom: float = rect.end.y * motif_scale.y + origin.y
|
|
|
|
|
var first_column: int = floori(world_left / SLAB_WIDTH)
|
|
|
|
|
var last_column: int = floori(world_right / SLAB_WIDTH)
|
|
|
|
|
var first_row: int = floori(world_top / SLAB_HEIGHT)
|
|
|
|
|
var last_row: int = floori(world_bottom / SLAB_HEIGHT)
|
|
|
|
|
var column_gap: float = 1.4 / motif_scale.x
|
|
|
|
|
var row_gap: float = 1.4 / motif_scale.y
|
|
|
|
|
var remaining: int = MAX_BACKGROUND_CELLS
|
|
|
|
|
for column: int in range(first_column, mini(last_column + 1, first_column + MAX_BACKGROUND_CELLS)):
|
|
|
|
|
var x: float = float(column) * SLAB_WIDTH
|
|
|
|
|
var local_x: float = (x - origin.x) / motif_scale.x
|
|
|
|
|
_draw_clipped_line(canvas, rect, Vector2(local_x, rect.position.y), Vector2(local_x, rect.end.y), Color("#68757A", 0.32), column_gap)
|
|
|
|
|
for row: int in range(first_row, mini(last_row + 1, first_row + MAX_BACKGROUND_CELLS)):
|
|
|
|
|
if remaining <= 0:
|
|
|
|
|
return
|
|
|
|
|
remaining -= 1
|
|
|
|
|
var seed: int = column * 92821 + row * 68917 + 51
|
|
|
|
|
var world_point := Vector2(x + 16.0 + _wood_hash(seed) * (SLAB_WIDTH - 32.0), float(row) * SLAB_HEIGHT + 14.0 + _wood_hash(seed + 1) * (SLAB_HEIGHT - 28.0))
|
|
|
|
|
var point := Vector2((world_point.x - origin.x) / motif_scale.x, (world_point.y - origin.y) / motif_scale.y)
|
|
|
|
|
if rect.grow(3.0).has_point(point):
|
|
|
|
|
var speckle: Color = Color("#E2E1D8") if _wood_hash(seed + 2) > 0.48 else Color("#677173")
|
|
|
|
|
canvas.draw_circle(point, (0.65 + _wood_hash(seed + 3) * 0.8) / motif_scale.y, _color_with_alpha(speckle, 0.34))
|
|
|
|
|
for row: int in range(first_row, mini(last_row + 1, first_row + MAX_BACKGROUND_CELLS)):
|
|
|
|
|
var y: float = float(row) * SLAB_HEIGHT
|
|
|
|
|
var local_y: float = (y - origin.y) / motif_scale.y
|
|
|
|
|
_draw_clipped_line(canvas, rect, Vector2(rect.position.x, local_y), Vector2(rect.end.x, local_y), Color("#68757A", 0.32), row_gap)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static func _draw_background_carpet(canvas: CanvasItem, rect: Rect2, origin: Vector2, motif_scale: Vector2, tint: Color) -> void:
|
|
|
|
|
const CELL_WIDTH: float = 34.0
|
|
|
|
|
const CELL_HEIGHT: float = 26.0
|
|
|
|
|
var world_left: float = rect.position.x * motif_scale.x + origin.x
|
|
|
|
|
var world_right: float = rect.end.x * motif_scale.x + origin.x
|
|
|
|
|
var world_top: float = rect.position.y * motif_scale.y + origin.y
|
|
|
|
|
var world_bottom: float = rect.end.y * motif_scale.y + origin.y
|
|
|
|
|
var first_column: int = floori(world_left / CELL_WIDTH)
|
|
|
|
|
var last_column: int = floori(world_right / CELL_WIDTH)
|
|
|
|
|
var first_row: int = floori(world_top / CELL_HEIGHT)
|
|
|
|
|
var last_row: int = floori(world_bottom / CELL_HEIGHT)
|
|
|
|
|
var remaining: int = MAX_BACKGROUND_CELLS
|
|
|
|
|
var natural: Color = default_tint(&"finish_background_carpet")
|
|
|
|
|
for row: int in range(first_row, last_row + 1):
|
|
|
|
|
for column: int in range(first_column, last_column + 1):
|
|
|
|
|
if remaining <= 0:
|
|
|
|
|
return
|
|
|
|
|
remaining -= 1
|
|
|
|
|
var seed: int = row * 92821 + column * 68917 + 71
|
|
|
|
|
var cell_left: float = float(column) * CELL_WIDTH
|
|
|
|
|
var cell_top: float = float(row) * CELL_HEIGHT
|
|
|
|
|
for fiber: int in 2:
|
|
|
|
|
var fiber_seed: int = seed + fiber * 53
|
|
|
|
|
var start_world := Vector2(cell_left + 3.0 + _wood_hash(fiber_seed) * (CELL_WIDTH - 6.0), cell_top + 3.0 + _wood_hash(fiber_seed + 1) * (CELL_HEIGHT - 6.0))
|
|
|
|
|
var end_world := start_world + Vector2(2.0 + _wood_hash(fiber_seed + 2) * 4.0, (_wood_hash(fiber_seed + 3) - 0.5) * 2.2)
|
|
|
|
|
var start := Vector2((start_world.x - origin.x) / motif_scale.x, (start_world.y - origin.y) / motif_scale.y)
|
|
|
|
|
var finish := Vector2((end_world.x - origin.x) / motif_scale.x, (end_world.y - origin.y) / motif_scale.y)
|
|
|
|
|
var source: Color = Color("#E7B8D2") if _wood_hash(fiber_seed + 4) > 0.52 else Color("#3E3044")
|
|
|
|
|
var fiber_color: Color = _material_color(source, tint, natural)
|
|
|
|
|
_draw_clipped_line(canvas, rect, start, finish, _color_with_alpha(fiber_color, 0.42), 0.85 / motif_scale.y)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static func _draw_wall_bricks(canvas: CanvasItem, rect: Rect2, origin: Vector2, motif_scale: Vector2, detail_scale: float, tint: Color) -> void:
|
|
|
|
|
var brick_world_w: float = WALL_BRICK_WIDTH * detail_scale
|
|
|
|
|
var brick_world_h: float = WALL_BRICK_HEIGHT * detail_scale
|
|
|
|
|
var brick_w: float = brick_world_w / motif_scale.x
|
|
|
|
|
var brick_h: float = brick_world_h / motif_scale.y
|
|
|
|
|
var world_left: float = rect.position.x * motif_scale.x + origin.x
|
|
|
|
|
var world_right: float = rect.end.x * motif_scale.x + origin.x
|
|
|
|
|
var world_top: float = rect.position.y * motif_scale.y + origin.y
|
|
|
|
|
var world_bottom: float = rect.end.y * motif_scale.y + origin.y
|
|
|
|
|
var first_row: int = floori(world_top / brick_world_h)
|
|
|
|
|
var last_row: int = floori((world_bottom - 0.001) / brick_world_h)
|
|
|
|
|
var mortar_gap := Vector2(3.5 * detail_scale / motif_scale.x, 3.5 * detail_scale / motif_scale.y)
|
|
|
|
|
var source_palette: Array[Color] = [
|
|
|
|
|
Color("#B65E3E"), Color("#C16B47"), Color("#A95337"),
|
|
|
|
|
Color("#BD704B"), Color("#AD583A"), Color("#C47A53"),
|
|
|
|
|
]
|
|
|
|
|
var palette: Array[Color] = []
|
|
|
|
|
for source_color: Color in source_palette:
|
|
|
|
|
palette.append(_material_color(source_color, tint, default_tint(&"finish_wall_brick")))
|
|
|
|
|
var row_count: int = mini(last_row - first_row + 1, MAX_WALL_BRICK_CELLS)
|
|
|
|
|
for row_offset: int in row_count:
|
|
|
|
|
var row: int = first_row + row_offset
|
|
|
|
|
var row_world_top: float = float(row) * brick_world_h
|
|
|
|
|
var row_local_top: float = (row_world_top - origin.y) / motif_scale.y
|
|
|
|
|
var stagger_world: float = brick_world_w * 0.5 if posmod(row, 2) == 1 else 0.0
|
|
|
|
|
var first_column: int = floori((world_left - stagger_world) / brick_world_w) - 1
|
|
|
|
|
var column_count: int = int(ceil(rect.size.x * motif_scale.x / brick_world_w)) + 2
|
|
|
|
|
for column_offset: int in column_count:
|
|
|
|
|
var column: int = first_column + column_offset
|
|
|
|
|
var seed: int = row * 92821 + column * 68917 + 31
|
|
|
|
|
var brick_world_left: float = float(column) * brick_world_w + stagger_world
|
|
|
|
|
var brick_local_left: float = (brick_world_left - origin.x) / motif_scale.x
|
|
|
|
|
var width_variation: float = 0.92 + _wood_hash(seed + 1) * 0.14
|
|
|
|
|
var height_variation: float = 0.92 + _wood_hash(seed + 2) * 0.12
|
|
|
|
|
var face_size := Vector2(brick_w * width_variation, brick_h * height_variation) - mortar_gap * 2.0
|
|
|
|
|
var center_jitter := Vector2(
|
|
|
|
|
(_wood_hash(seed + 3) - 0.5) * 2.0 * mortar_gap.x * 0.3,
|
|
|
|
|
(_wood_hash(seed + 4) - 0.5) * 2.0 * mortar_gap.y * 0.3
|
|
|
|
|
)
|
|
|
|
|
var face_rect := Rect2(
|
|
|
|
|
Vector2(brick_local_left, row_local_top) + mortar_gap + center_jitter,
|
|
|
|
|
face_size
|
|
|
|
|
)
|
|
|
|
|
if face_rect.end.x < rect.position.x or face_rect.position.x > rect.end.x:
|
|
|
|
|
continue
|
|
|
|
|
if face_rect.end.y < rect.position.y or face_rect.position.y > rect.end.y:
|
|
|
|
|
continue
|
|
|
|
|
var roughness := Vector2(1.7 * detail_scale / motif_scale.x, 1.2 * detail_scale / motif_scale.y)
|
|
|
|
|
var outline: PackedVector2Array = _rough_brick_outline(face_rect, seed, roughness)
|
|
|
|
|
var shadow_offset := Vector2(1.3 * detail_scale / motif_scale.x, 1.8 * detail_scale / motif_scale.y)
|
|
|
|
|
var shadow_points: PackedVector2Array = _clip_polygon_to_rect(_offset_polygon(outline, shadow_offset), rect)
|
|
|
|
|
if shadow_points.size() >= 3:
|
|
|
|
|
canvas.draw_colored_polygon(shadow_points, _color_with_alpha(_material_color(Color("#72503E"), tint, default_tint(&"finish_wall_brick")), 0.40))
|
|
|
|
|
var face_points: PackedVector2Array = _clip_polygon_to_rect(outline, rect)
|
|
|
|
|
if face_points.size() < 3:
|
|
|
|
|
continue
|
|
|
|
|
var color_index: int = int(_wood_hash(seed + 5) * float(palette.size()))
|
|
|
|
|
var face_color: Color = palette[color_index]
|
|
|
|
|
canvas.draw_colored_polygon(face_points, face_color)
|
|
|
|
|
var closed_outline := face_points.duplicate()
|
|
|
|
|
closed_outline.append(face_points[0])
|
|
|
|
|
_draw_clipped_polyline(
|
|
|
|
|
canvas, rect, closed_outline, _color_with_alpha(_material_color(Color("#784631"), tint, default_tint(&"finish_wall_brick")), 0.30), 1.2 * detail_scale / motif_scale.y
|
|
|
|
|
)
|
|
|
|
|
var upper_edge := PackedVector2Array()
|
|
|
|
|
for point_index: int in mini(5, outline.size()):
|
|
|
|
|
upper_edge.append(outline[point_index])
|
|
|
|
|
_draw_clipped_polyline(
|
|
|
|
|
canvas, rect, upper_edge, _color_with_alpha(_material_color(Color("#F0B27C"), tint, default_tint(&"finish_wall_brick")), 0.58), 1.15 * detail_scale / motif_scale.y
|
|
|
|
|
)
|
|
|
|
|
var facet := PackedVector2Array([
|
|
|
|
|
Vector2(face_rect.position.x + face_rect.size.x * 0.06, face_rect.position.y + face_rect.size.y * 0.20),
|
|
|
|
|
Vector2(face_rect.position.x + face_rect.size.x * 0.40, face_rect.position.y + face_rect.size.y * 0.12),
|
|
|
|
|
Vector2(face_rect.position.x + face_rect.size.x * 0.68, face_rect.position.y + face_rect.size.y * 0.22),
|
|
|
|
|
Vector2(face_rect.position.x + face_rect.size.x * 0.34, face_rect.position.y + face_rect.size.y * 0.40),
|
|
|
|
|
])
|
|
|
|
|
var facet_points: PackedVector2Array = _clip_polygon_to_rect(facet, rect)
|
|
|
|
|
if facet_points.size() >= 3:
|
|
|
|
|
canvas.draw_colored_polygon(facet_points, _color_with_alpha(_material_color(Color("#E49A68"), tint, default_tint(&"finish_wall_brick")), 0.20))
|
|
|
|
|
_draw_wall_brick_texture(canvas, rect, face_rect, seed, detail_scale, motif_scale, tint)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static func _rough_brick_outline(rect: Rect2, seed: int, roughness: Vector2) -> PackedVector2Array:
|
|
|
|
|
var perimeter: Array[Vector2] = [
|
|
|
|
|
Vector2(0.02, 0.05), Vector2(0.22, 0.00), Vector2(0.45, 0.04), Vector2(0.68, 0.00),
|
|
|
|
|
Vector2(0.96, 0.03), Vector2(1.00, 0.22), Vector2(0.97, 0.48), Vector2(1.00, 0.73),
|
|
|
|
|
Vector2(0.97, 0.95), Vector2(0.72, 1.00), Vector2(0.48, 0.96), Vector2(0.22, 1.00),
|
|
|
|
|
Vector2(0.03, 0.96), Vector2(0.00, 0.73), Vector2(0.04, 0.48), Vector2(0.00, 0.22),
|
|
|
|
|
]
|
|
|
|
|
var points := PackedVector2Array()
|
|
|
|
|
for point_index: int in perimeter.size():
|
|
|
|
|
var normalized_point: Vector2 = perimeter[point_index]
|
|
|
|
|
var jitter := Vector2(
|
|
|
|
|
(_wood_hash(seed + point_index * 2 + 11) - 0.5) * 2.0 * roughness.x,
|
|
|
|
|
(_wood_hash(seed + point_index * 2 + 12) - 0.5) * 2.0 * roughness.y
|
|
|
|
|
)
|
|
|
|
|
points.append(rect.position + normalized_point * rect.size + jitter)
|
|
|
|
|
return points
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static func _draw_wall_brick_texture(
|
|
|
|
|
canvas: CanvasItem,
|
|
|
|
|
clip_rect: Rect2,
|
|
|
|
|
face_rect: Rect2,
|
|
|
|
|
seed: int,
|
|
|
|
|
detail_scale: float,
|
|
|
|
|
motif_scale: Vector2,
|
|
|
|
|
tint: Color
|
|
|
|
|
) -> void:
|
|
|
|
|
var mark_count: int = 4 + int(_wood_hash(seed + 201) * 4.0)
|
|
|
|
|
var natural: Color = default_tint(&"finish_wall_brick")
|
|
|
|
|
var dark_ochre: Color = _material_color(Color("#74412D"), tint, natural)
|
|
|
|
|
var warm_clay: Color = _material_color(Color("#E09A68"), tint, natural)
|
|
|
|
|
for mark_index: int in mark_count:
|
|
|
|
|
var mark_seed: int = seed + mark_index * 37 + 211
|
|
|
|
|
var start_x: float = face_rect.position.x + face_rect.size.x * (0.09 + _wood_hash(mark_seed) * 0.72)
|
|
|
|
|
var center_y: float = face_rect.position.y + face_rect.size.y * (0.20 + _wood_hash(mark_seed + 1) * 0.63)
|
|
|
|
|
var length: float = face_rect.size.x * (0.08 + _wood_hash(mark_seed + 2) * 0.22)
|
|
|
|
|
var wave: float = (0.7 + _wood_hash(mark_seed + 3) * 1.8) * detail_scale / motif_scale.y
|
|
|
|
|
var points := PackedVector2Array([
|
|
|
|
|
Vector2(start_x, center_y),
|
|
|
|
|
Vector2(start_x + length * 0.48, center_y + wave),
|
|
|
|
|
Vector2(start_x + length, center_y - wave * 0.35),
|
|
|
|
|
])
|
|
|
|
|
var light_mark: bool = _wood_hash(mark_seed + 4) > 0.72
|
|
|
|
|
var mark_color: Color = warm_clay if light_mark else dark_ochre
|
|
|
|
|
var alpha: float = 0.20 + _wood_hash(mark_seed + 5) * 0.25
|
|
|
|
|
var width: float = (0.8 + _wood_hash(mark_seed + 6) * 1.6) * detail_scale / motif_scale.y
|
|
|
|
|
_draw_clipped_polyline(canvas, clip_rect, points, _color_with_alpha(mark_color, alpha), width)
|
|
|
|
|
var pore_count: int = 3 + int(_wood_hash(seed + 401) * 4.0)
|
|
|
|
|
for pore_index: int in pore_count:
|
|
|
|
|
var pore_seed: int = seed + pore_index * 53 + 419
|
|
|
|
|
var pore := Vector2(
|
|
|
|
|
face_rect.position.x + face_rect.size.x * (0.10 + _wood_hash(pore_seed) * 0.80),
|
|
|
|
|
face_rect.position.y + face_rect.size.y * (0.15 + _wood_hash(pore_seed + 1) * 0.70)
|
|
|
|
|
)
|
|
|
|
|
var radius: float = (0.55 + _wood_hash(pore_seed + 2) * 0.8) * detail_scale / motif_scale.y
|
|
|
|
|
var pore_color: Color = warm_clay if _wood_hash(pore_seed + 3) > 0.62 else dark_ochre
|
|
|
|
|
canvas.draw_circle(pore, radius, _color_with_alpha(pore_color, 0.38))
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static func _offset_polygon(points: PackedVector2Array, offset: Vector2) -> PackedVector2Array:
|
|
|
|
|
var result := PackedVector2Array()
|
|
|
|
|
for point: Vector2 in points:
|
|
|
|
|
result.append(point + offset)
|
|
|
|
|
return result
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static func _clip_polygon_to_rect(points: PackedVector2Array, rect: Rect2) -> PackedVector2Array:
|
|
|
|
|
var clipped := points
|
|
|
|
|
for edge: int in 4:
|
|
|
|
|
clipped = _clip_polygon_to_edge(clipped, rect, edge)
|
|
|
|
|
if clipped.is_empty():
|
|
|
|
|
return clipped
|
|
|
|
|
return clipped
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static func _clip_polygon_to_edge(points: PackedVector2Array, rect: Rect2, edge: int) -> PackedVector2Array:
|
|
|
|
|
var result := PackedVector2Array()
|
|
|
|
|
if points.is_empty():
|
|
|
|
|
return result
|
|
|
|
|
var previous: Vector2 = points[points.size() - 1]
|
|
|
|
|
var previous_inside: bool = _point_inside_rect_edge(previous, rect, edge)
|
|
|
|
|
for current: Vector2 in points:
|
|
|
|
|
var current_inside: bool = _point_inside_rect_edge(current, rect, edge)
|
|
|
|
|
if current_inside:
|
|
|
|
|
if not previous_inside:
|
|
|
|
|
result.append(_rect_edge_intersection(previous, current, rect, edge))
|
|
|
|
|
result.append(current)
|
|
|
|
|
elif previous_inside:
|
|
|
|
|
result.append(_rect_edge_intersection(previous, current, rect, edge))
|
|
|
|
|
previous = current
|
|
|
|
|
previous_inside = current_inside
|
|
|
|
|
return result
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static func _point_inside_rect_edge(point: Vector2, rect: Rect2, edge: int) -> bool:
|
|
|
|
|
match edge:
|
|
|
|
|
0:
|
|
|
|
|
return point.x >= rect.position.x
|
|
|
|
|
1:
|
|
|
|
|
return point.x <= rect.end.x
|
|
|
|
|
2:
|
|
|
|
|
return point.y >= rect.position.y
|
|
|
|
|
_:
|
|
|
|
|
return point.y <= rect.end.y
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static func _rect_edge_intersection(from: Vector2, to: Vector2, rect: Rect2, edge: int) -> Vector2:
|
|
|
|
|
if edge <= 1:
|
|
|
|
|
var boundary_x: float = rect.position.x if edge == 0 else rect.end.x
|
|
|
|
|
var ratio_x: float = (boundary_x - from.x) / (to.x - from.x)
|
|
|
|
|
return Vector2(boundary_x, lerpf(from.y, to.y, ratio_x))
|
|
|
|
|
var boundary_y: float = rect.position.y if edge == 2 else rect.end.y
|
|
|
|
|
var ratio_y: float = (boundary_y - from.y) / (to.y - from.y)
|
|
|
|
|
return Vector2(lerpf(from.x, to.x, ratio_y), boundary_y)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static func _draw_bricks(canvas: CanvasItem, rect: Rect2, origin: Vector2, base: Color, motif_scale: Vector2, detail_scale: float = 1.0) -> void:
|
|
|
|
|
var brick_world_w: float = BRICK_WIDTH * detail_scale
|
|
|
|
|
var brick_world_h: float = BRICK_HEIGHT * detail_scale
|
|
|
|
|