mirror of
https://github.com/Relintai/material-maker.git
synced 2025-01-25 18:59:18 +01:00
Added new patterns for bricks
Added a Running Bond variant, HerringBone, Basket Weave and Spanish bond patterns to the bricks generator. Shader was refactored to make it easy to add new patterns made of axis-aligned bricks.
This commit is contained in:
parent
0d0f862a99
commit
ddbd69ea25
@ -145,21 +145,99 @@ vec2 transform_norepeat(vec2 uv, vec2 translate, float rotate, vec2 scale) {
|
|||||||
return clamp(transform(uv, translate, rotate, scale), vec2(0.0), vec2(1.0));
|
return clamp(transform(uv, translate, rotate, scale), vec2(0.0), vec2(1.0));
|
||||||
}
|
}
|
||||||
|
|
||||||
vec3 bricks(vec2 uv, vec2 count, float offset, float mortar, float bevel) {
|
vec3 brick(vec2 uv, vec2 bmin, vec2 bmax, float mortar, float bevel) {
|
||||||
|
float color = 0.5;
|
||||||
|
vec2 c1 = (uv-bmin-vec2(mortar))/bevel;
|
||||||
|
vec2 c2 = (bmax-uv-vec2(mortar))/bevel;
|
||||||
|
vec2 c = min(c1, c2);
|
||||||
|
color = clamp(min(c.x, c.y), 0.0, 1.0);
|
||||||
|
return vec3(color, bmin);
|
||||||
|
}
|
||||||
|
|
||||||
|
vec3 bricks_rb(vec2 uv, vec2 count, float repeat, float offset, float mortar, float bevel) {
|
||||||
|
count *= repeat;
|
||||||
mortar /= max(count.x, count.y);
|
mortar /= max(count.x, count.y);
|
||||||
bevel /= max(count.x, count.y);
|
bevel /= max(count.x, count.y);
|
||||||
float x = uv.x*count.x+offset*step(0.5, fract(uv.y*count.y*0.5));
|
float x_offset = offset*step(0.5, fract(uv.y*count.y*0.5));
|
||||||
float fract_x = fract(x);
|
vec2 bmin = floor(vec2(uv.x*count.x-x_offset, uv.y*count.y));
|
||||||
float slope_x = 1.0/(bevel*count.x);
|
bmin.x += x_offset;
|
||||||
float off = 0.5*mortar/bevel;
|
bmin /= count;
|
||||||
float f1 = fract_x*slope_x-off;
|
return brick(uv, bmin, bmin+vec2(1.0)/count, mortar, bevel);
|
||||||
float f2 = (1.0-fract_x)*slope_x-off;
|
}
|
||||||
float y = uv.y*count.y;
|
|
||||||
float fract_y = fract(uv.y*count.y);
|
vec3 bricks_rb2(vec2 uv, vec2 count, float repeat, float offset, float mortar, float bevel) {
|
||||||
float slope_y = 1.0/(bevel*count.y);
|
count *= repeat;
|
||||||
float f3 = fract_y*slope_y-off;
|
mortar /= max(2.0*count.x, count.y);
|
||||||
float f4 = (1.0-fract_y)*slope_y-off;
|
bevel /= max(2.0*count.x, count.y);
|
||||||
return vec3(max(0.0, min(1.0, min(min(f1, f2), min(f3, f4)))), floor(mod(x, count.x)), floor(mod(y, count.y)));
|
float x_offset = offset*step(0.5, fract(uv.y*count.y*0.5));
|
||||||
|
count.x = count.x*(1.0+step(0.5, fract(uv.y*count.y*0.5)));
|
||||||
|
vec2 bmin = floor(vec2(uv.x*count.x-x_offset, uv.y*count.y));
|
||||||
|
bmin.x += x_offset;
|
||||||
|
bmin /= count;
|
||||||
|
return brick(uv, bmin, bmin+vec2(1.0)/count, mortar, bevel);
|
||||||
|
}
|
||||||
|
|
||||||
|
vec3 bricks_hb(vec2 uv, vec2 count, float repeat, float offset, float mortar, float bevel) {
|
||||||
|
float pc = count.x+count.y;
|
||||||
|
float c = pc*repeat;
|
||||||
|
mortar /= c;
|
||||||
|
bevel /= c;
|
||||||
|
vec2 corner = floor(uv*c);
|
||||||
|
float cdiff = mod(corner.x-corner.y, pc);
|
||||||
|
if (cdiff < count.x) {
|
||||||
|
return brick(uv, (corner-vec2(cdiff, 0.0))/c, (corner-vec2(cdiff, 0.0)+vec2(count.x, 1.0))/c, mortar, bevel);
|
||||||
|
} else {
|
||||||
|
return brick(uv, (corner-vec2(0.0, pc-cdiff-1.0))/c, (corner-vec2(0.0, pc-cdiff-1.0)+vec2(1.0, count.y))/c, mortar, bevel);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
vec3 bricks_bw(vec2 uv, vec2 count, float repeat, float offset, float mortar, float bevel) {
|
||||||
|
vec2 c = 2.0*count*repeat;
|
||||||
|
float mc = max(c.x, c.y);
|
||||||
|
mortar /= mc;
|
||||||
|
bevel /= mc;
|
||||||
|
vec2 corner1 = floor(uv*c);
|
||||||
|
vec2 corner2 = count*floor(repeat*2.0*uv);
|
||||||
|
float cdiff = mod(dot(floor(repeat*2.0*uv), vec2(1.0)), 2.0);
|
||||||
|
vec2 corner;
|
||||||
|
vec2 size;
|
||||||
|
if (cdiff == 0.0) {
|
||||||
|
corner = vec2(corner1.x, corner2.y);
|
||||||
|
size = vec2(1.0, count.y);
|
||||||
|
} else {
|
||||||
|
corner = vec2(corner2.x, corner1.y);
|
||||||
|
size = vec2(count.x, 1.0);
|
||||||
|
}
|
||||||
|
return brick(uv, corner/c, (corner+size)/c, mortar, bevel);
|
||||||
|
}
|
||||||
|
|
||||||
|
vec3 bricks_sb(vec2 uv, vec2 count, float repeat, float offset, float mortar, float bevel) {
|
||||||
|
vec2 c = (count+vec2(1.0))*repeat;
|
||||||
|
float mc = max(c.x, c.y);
|
||||||
|
mortar /= mc;
|
||||||
|
bevel /= mc;
|
||||||
|
vec2 corner1 = floor(uv*c);
|
||||||
|
vec2 corner2 = (count+vec2(1.0))*floor(repeat*uv);
|
||||||
|
vec2 rcorner = corner1 - corner2;
|
||||||
|
vec2 corner;
|
||||||
|
vec2 size;
|
||||||
|
if (rcorner.x == 0.0 && rcorner.y < count.y) {
|
||||||
|
corner = corner2;
|
||||||
|
size = vec2(1.0, count.y);
|
||||||
|
} else if (rcorner.y == 0.0) {
|
||||||
|
corner = corner2+vec2(1.0, 0.0);
|
||||||
|
size = vec2(count.x, 1.0);
|
||||||
|
} else if (rcorner.x == count.x) {
|
||||||
|
corner = corner2+vec2(count.x, 1.0);
|
||||||
|
size = vec2(1.0, count.y);
|
||||||
|
} else if (rcorner.y == count.y) {
|
||||||
|
corner = corner2+vec2(0.0, count.y);
|
||||||
|
size = vec2(count.x, 1.0);
|
||||||
|
} else {
|
||||||
|
corner = corner2+vec2(1.0);
|
||||||
|
size = vec2(count.x-1.0, count.y-1.0);
|
||||||
|
}
|
||||||
|
return brick(uv, corner/c, (corner+size)/c, mortar, bevel);
|
||||||
}
|
}
|
||||||
|
|
||||||
float colored_bricks(vec2 uv, vec2 count, float offset) {
|
float colored_bricks(vec2 uv, vec2 count, float offset) {
|
||||||
|
@ -1,27 +1,42 @@
|
|||||||
tool
|
tool
|
||||||
extends "res://addons/procedural_material/node_base.gd"
|
extends "res://addons/procedural_material/node_base.gd"
|
||||||
|
|
||||||
|
var pattern = 0
|
||||||
|
var repeat
|
||||||
var rows
|
var rows
|
||||||
var columns
|
var columns
|
||||||
var row_offset
|
var row_offset
|
||||||
var mortar
|
var mortar
|
||||||
var bevel
|
var bevel
|
||||||
|
|
||||||
|
const BRICK_PATTERNS = [
|
||||||
|
{ name="Running bond", suffix="rb", has_offset=true, has_repeat=false },
|
||||||
|
{ name="Running bond (2)", suffix="rb2", has_offset=true, has_repeat=false },
|
||||||
|
{ name="HerringBone", suffix="hb", has_offset=false, has_repeat=true },
|
||||||
|
{ name="Basket weave", suffix="bw", has_offset=false, has_repeat=true },
|
||||||
|
{ name="Spanish bond", suffix="sb", has_offset=false, has_repeat=true }
|
||||||
|
]
|
||||||
|
|
||||||
func _ready():
|
func _ready():
|
||||||
set_slot(0, false, 0, Color(0.5, 0.5, 1), true, 0, Color(0.5, 0.5, 1))
|
$pattern.clear()
|
||||||
initialize_properties([ $HBoxContainer1/rows, $HBoxContainer2/columns, $HBoxContainer3/row_offset, $HBoxContainer4/mortar, $HBoxContainer5/bevel ])
|
for p in BRICK_PATTERNS:
|
||||||
|
$pattern.add_item(p.name)
|
||||||
|
initialize_properties([ $pattern, $HBoxContainer1/rows, $HBoxContainer2/columns, $HBoxContainer6/repeat, $HBoxContainer3/row_offset, $HBoxContainer4/mortar, $HBoxContainer5/bevel ])
|
||||||
|
|
||||||
func _get_shader_code(uv, slot = 0):
|
func _get_shader_code(uv, slot = 0):
|
||||||
var rv = { defs="", code="" }
|
var rv = { defs="", code="" }
|
||||||
if generated_variants.empty():
|
if generated_variants.empty():
|
||||||
rv.defs = "vec3 "+name+"_xyz(vec2 uv) { return bricks(uv, vec2("+str(columns)+", "+str(rows)+"), "+str(row_offset)+", "+str(mortar)+", "+str(max(0.001, bevel))+"); }\n"
|
rv.defs = "vec3 %s_xyz(vec2 uv) { return bricks_%s(uv, vec2(%d, %d), %.9f, %.9f, %.9f, %.9f); }\n" % [ name, BRICK_PATTERNS[pattern].suffix, columns, rows, repeat, row_offset, mortar, max(0.001, bevel) ]
|
||||||
var variant_index = generated_variants.find(uv)
|
var variant_index = generated_variants.find(uv)
|
||||||
if variant_index == -1:
|
if variant_index == -1:
|
||||||
variant_index = generated_variants.size()
|
variant_index = generated_variants.size()
|
||||||
generated_variants.append(uv)
|
generated_variants.append(uv)
|
||||||
rv.code = "vec3 "+name+"_"+str(variant_index)+"_xyz = "+name+"_xyz("+uv+");\n"
|
rv.code = "vec3 %s_%d_xyz = %s_xyz(%s);\n" % [ name, variant_index, name, uv ]
|
||||||
if slot == 0:
|
if slot == 0:
|
||||||
rv.f = name+"_"+str(variant_index)+"_xyz.x"
|
rv.f = "%s_%d_xyz.x" % [ name, variant_index ]
|
||||||
else:
|
else:
|
||||||
rv.rgb = "rand3("+name+"_"+str(variant_index)+"_xyz.yz)"
|
rv.rgb = "rand3(%s_%d_xyz.yz+vec2(%.9f))" % [ name, variant_index, get_seed() ]
|
||||||
return rv
|
return rv
|
||||||
|
|
||||||
|
func _on_offset_changed():
|
||||||
|
update_shaders()
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
[sub_resource type="Theme" id=1]
|
[sub_resource type="Theme" id=1]
|
||||||
|
|
||||||
|
|
||||||
[node name="Bricks" type="GraphNode"]
|
[node name="Bricks" type="GraphNode" index="0"]
|
||||||
|
|
||||||
anchor_left = 0.0
|
anchor_left = 0.0
|
||||||
anchor_top = 0.0
|
anchor_top = 0.0
|
||||||
@ -58,10 +58,22 @@ slot/4/left_color = Color( 1, 1, 1, 1 )
|
|||||||
slot/4/right_enabled = false
|
slot/4/right_enabled = false
|
||||||
slot/4/right_type = 0
|
slot/4/right_type = 0
|
||||||
slot/4/right_color = Color( 1, 1, 1, 1 )
|
slot/4/right_color = Color( 1, 1, 1, 1 )
|
||||||
|
slot/5/left_enabled = false
|
||||||
|
slot/5/left_type = 0
|
||||||
|
slot/5/left_color = Color( 1, 1, 1, 1 )
|
||||||
|
slot/5/right_enabled = false
|
||||||
|
slot/5/right_type = 0
|
||||||
|
slot/5/right_color = Color( 1, 1, 1, 1 )
|
||||||
|
slot/6/left_enabled = false
|
||||||
|
slot/6/left_type = 0
|
||||||
|
slot/6/left_color = Color( 1, 1, 1, 1 )
|
||||||
|
slot/6/right_enabled = false
|
||||||
|
slot/6/right_type = 0
|
||||||
|
slot/6/right_color = Color( 1, 1, 1, 1 )
|
||||||
script = ExtResource( 1 )
|
script = ExtResource( 1 )
|
||||||
_sections_unfolded = [ "Mouse", "Theme", "slot", "slot/0", "slot/1" ]
|
_sections_unfolded = [ "Mouse", "Theme", "slot", "slot/0", "slot/1" ]
|
||||||
|
|
||||||
[node name="HBoxContainer1" type="HBoxContainer" parent="." index="0"]
|
[node name="pattern" type="OptionButton" parent="." index="0"]
|
||||||
|
|
||||||
anchor_left = 0.0
|
anchor_left = 0.0
|
||||||
anchor_top = 0.0
|
anchor_top = 0.0
|
||||||
@ -70,7 +82,100 @@ anchor_bottom = 0.0
|
|||||||
margin_left = 16.0
|
margin_left = 16.0
|
||||||
margin_top = 24.0
|
margin_top = 24.0
|
||||||
margin_right = 154.0
|
margin_right = 154.0
|
||||||
margin_bottom = 48.0
|
margin_bottom = 44.0
|
||||||
|
rect_pivot_offset = Vector2( 0, 0 )
|
||||||
|
rect_clip_content = false
|
||||||
|
focus_mode = 2
|
||||||
|
mouse_filter = 0
|
||||||
|
mouse_default_cursor_shape = 0
|
||||||
|
size_flags_horizontal = 3
|
||||||
|
size_flags_vertical = 1
|
||||||
|
toggle_mode = false
|
||||||
|
action_mode = 0
|
||||||
|
enabled_focus_mode = 2
|
||||||
|
shortcut = null
|
||||||
|
group = null
|
||||||
|
flat = false
|
||||||
|
align = 0
|
||||||
|
items = [ ]
|
||||||
|
selected = -1
|
||||||
|
_sections_unfolded = [ "Size Flags" ]
|
||||||
|
|
||||||
|
[node name="HBoxContainer6" type="HBoxContainer" parent="." index="1"]
|
||||||
|
|
||||||
|
anchor_left = 0.0
|
||||||
|
anchor_top = 0.0
|
||||||
|
anchor_right = 0.0
|
||||||
|
anchor_bottom = 0.0
|
||||||
|
margin_left = 16.0
|
||||||
|
margin_top = 44.0
|
||||||
|
margin_right = 154.0
|
||||||
|
margin_bottom = 68.0
|
||||||
|
rect_pivot_offset = Vector2( 0, 0 )
|
||||||
|
rect_clip_content = false
|
||||||
|
mouse_filter = 1
|
||||||
|
mouse_default_cursor_shape = 0
|
||||||
|
size_flags_horizontal = 1
|
||||||
|
size_flags_vertical = 1
|
||||||
|
alignment = 0
|
||||||
|
|
||||||
|
[node name="Label1" type="Label" parent="HBoxContainer6" index="0"]
|
||||||
|
|
||||||
|
anchor_left = 0.0
|
||||||
|
anchor_top = 0.0
|
||||||
|
anchor_right = 0.0
|
||||||
|
anchor_bottom = 0.0
|
||||||
|
margin_top = 5.0
|
||||||
|
margin_right = 60.0
|
||||||
|
margin_bottom = 19.0
|
||||||
|
rect_pivot_offset = Vector2( 0, 0 )
|
||||||
|
rect_clip_content = false
|
||||||
|
mouse_filter = 2
|
||||||
|
mouse_default_cursor_shape = 0
|
||||||
|
size_flags_horizontal = 3
|
||||||
|
size_flags_vertical = 4
|
||||||
|
text = "Repeat:"
|
||||||
|
percent_visible = 1.0
|
||||||
|
lines_skipped = 0
|
||||||
|
max_lines_visible = -1
|
||||||
|
|
||||||
|
[node name="repeat" type="SpinBox" parent="HBoxContainer6" index="1"]
|
||||||
|
|
||||||
|
anchor_left = 0.0
|
||||||
|
anchor_top = 0.0
|
||||||
|
anchor_right = 0.0
|
||||||
|
anchor_bottom = 0.0
|
||||||
|
margin_left = 64.0
|
||||||
|
margin_right = 138.0
|
||||||
|
margin_bottom = 24.0
|
||||||
|
rect_pivot_offset = Vector2( 0, 0 )
|
||||||
|
rect_clip_content = false
|
||||||
|
mouse_filter = 0
|
||||||
|
mouse_default_cursor_shape = 0
|
||||||
|
size_flags_horizontal = 9
|
||||||
|
size_flags_vertical = 1
|
||||||
|
min_value = 1.0
|
||||||
|
max_value = 8.0
|
||||||
|
step = 1.0
|
||||||
|
page = 0.0
|
||||||
|
value = 1.0
|
||||||
|
exp_edit = false
|
||||||
|
rounded = false
|
||||||
|
editable = true
|
||||||
|
prefix = ""
|
||||||
|
suffix = ""
|
||||||
|
_sections_unfolded = [ "Caret", "Placeholder" ]
|
||||||
|
|
||||||
|
[node name="HBoxContainer1" type="HBoxContainer" parent="." index="2"]
|
||||||
|
|
||||||
|
anchor_left = 0.0
|
||||||
|
anchor_top = 0.0
|
||||||
|
anchor_right = 0.0
|
||||||
|
anchor_bottom = 0.0
|
||||||
|
margin_left = 16.0
|
||||||
|
margin_top = 69.0
|
||||||
|
margin_right = 154.0
|
||||||
|
margin_bottom = 93.0
|
||||||
rect_pivot_offset = Vector2( 0, 0 )
|
rect_pivot_offset = Vector2( 0, 0 )
|
||||||
rect_clip_content = false
|
rect_clip_content = false
|
||||||
mouse_filter = 1
|
mouse_filter = 1
|
||||||
@ -126,16 +231,16 @@ prefix = ""
|
|||||||
suffix = ""
|
suffix = ""
|
||||||
_sections_unfolded = [ "Caret", "Placeholder" ]
|
_sections_unfolded = [ "Caret", "Placeholder" ]
|
||||||
|
|
||||||
[node name="HBoxContainer2" type="HBoxContainer" parent="." index="1"]
|
[node name="HBoxContainer2" type="HBoxContainer" parent="." index="3"]
|
||||||
|
|
||||||
anchor_left = 0.0
|
anchor_left = 0.0
|
||||||
anchor_top = 0.0
|
anchor_top = 0.0
|
||||||
anchor_right = 0.0
|
anchor_right = 0.0
|
||||||
anchor_bottom = 0.0
|
anchor_bottom = 0.0
|
||||||
margin_left = 16.0
|
margin_left = 16.0
|
||||||
margin_top = 48.0
|
margin_top = 94.0
|
||||||
margin_right = 154.0
|
margin_right = 154.0
|
||||||
margin_bottom = 72.0
|
margin_bottom = 118.0
|
||||||
rect_pivot_offset = Vector2( 0, 0 )
|
rect_pivot_offset = Vector2( 0, 0 )
|
||||||
rect_clip_content = false
|
rect_clip_content = false
|
||||||
mouse_filter = 1
|
mouse_filter = 1
|
||||||
@ -191,16 +296,16 @@ prefix = ""
|
|||||||
suffix = ""
|
suffix = ""
|
||||||
_sections_unfolded = [ "Caret", "Placeholder" ]
|
_sections_unfolded = [ "Caret", "Placeholder" ]
|
||||||
|
|
||||||
[node name="HBoxContainer3" type="HBoxContainer" parent="." index="2"]
|
[node name="HBoxContainer3" type="HBoxContainer" parent="." index="4"]
|
||||||
|
|
||||||
anchor_left = 0.0
|
anchor_left = 0.0
|
||||||
anchor_top = 0.0
|
anchor_top = 0.0
|
||||||
anchor_right = 0.0
|
anchor_right = 0.0
|
||||||
anchor_bottom = 0.0
|
anchor_bottom = 0.0
|
||||||
margin_left = 16.0
|
margin_left = 16.0
|
||||||
margin_top = 73.0
|
margin_top = 119.0
|
||||||
margin_right = 154.0
|
margin_right = 154.0
|
||||||
margin_bottom = 97.0
|
margin_bottom = 143.0
|
||||||
rect_pivot_offset = Vector2( 0, 0 )
|
rect_pivot_offset = Vector2( 0, 0 )
|
||||||
rect_clip_content = false
|
rect_clip_content = false
|
||||||
mouse_filter = 1
|
mouse_filter = 1
|
||||||
@ -256,16 +361,16 @@ prefix = ""
|
|||||||
suffix = ""
|
suffix = ""
|
||||||
_sections_unfolded = [ "Caret", "Placeholder" ]
|
_sections_unfolded = [ "Caret", "Placeholder" ]
|
||||||
|
|
||||||
[node name="HBoxContainer4" type="HBoxContainer" parent="." index="3"]
|
[node name="HBoxContainer4" type="HBoxContainer" parent="." index="5"]
|
||||||
|
|
||||||
anchor_left = 0.0
|
anchor_left = 0.0
|
||||||
anchor_top = 0.0
|
anchor_top = 0.0
|
||||||
anchor_right = 0.0
|
anchor_right = 0.0
|
||||||
anchor_bottom = 0.0
|
anchor_bottom = 0.0
|
||||||
margin_left = 16.0
|
margin_left = 16.0
|
||||||
margin_top = 98.0
|
margin_top = 144.0
|
||||||
margin_right = 154.0
|
margin_right = 154.0
|
||||||
margin_bottom = 122.0
|
margin_bottom = 168.0
|
||||||
rect_pivot_offset = Vector2( 0, 0 )
|
rect_pivot_offset = Vector2( 0, 0 )
|
||||||
rect_clip_content = false
|
rect_clip_content = false
|
||||||
mouse_filter = 1
|
mouse_filter = 1
|
||||||
@ -321,16 +426,16 @@ prefix = ""
|
|||||||
suffix = ""
|
suffix = ""
|
||||||
_sections_unfolded = [ "Caret", "Placeholder" ]
|
_sections_unfolded = [ "Caret", "Placeholder" ]
|
||||||
|
|
||||||
[node name="HBoxContainer5" type="HBoxContainer" parent="." index="4"]
|
[node name="HBoxContainer5" type="HBoxContainer" parent="." index="6"]
|
||||||
|
|
||||||
anchor_left = 0.0
|
anchor_left = 0.0
|
||||||
anchor_top = 0.0
|
anchor_top = 0.0
|
||||||
anchor_right = 0.0
|
anchor_right = 0.0
|
||||||
anchor_bottom = 0.0
|
anchor_bottom = 0.0
|
||||||
margin_left = 16.0
|
margin_left = 16.0
|
||||||
margin_top = 123.0
|
margin_top = 169.0
|
||||||
margin_right = 154.0
|
margin_right = 154.0
|
||||||
margin_bottom = 147.0
|
margin_bottom = 193.0
|
||||||
rect_pivot_offset = Vector2( 0, 0 )
|
rect_pivot_offset = Vector2( 0, 0 )
|
||||||
rect_clip_content = false
|
rect_clip_content = false
|
||||||
mouse_filter = 1
|
mouse_filter = 1
|
||||||
@ -386,4 +491,6 @@ prefix = ""
|
|||||||
suffix = ""
|
suffix = ""
|
||||||
_sections_unfolded = [ "Caret", "Placeholder" ]
|
_sections_unfolded = [ "Caret", "Placeholder" ]
|
||||||
|
|
||||||
|
[connection signal="offset_changed" from="." to="." method="_on_offset_changed"]
|
||||||
|
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user