Refactor font out to own type
This commit is contained in:
+200
@@ -0,0 +1,200 @@
|
|||||||
|
const V2 = @import("V2.zig");
|
||||||
|
const Image = @import("Image.zig");
|
||||||
|
|
||||||
|
const Self = @This();
|
||||||
|
|
||||||
|
glyph_width: i32,
|
||||||
|
glyph_height: i32,
|
||||||
|
image: Image,
|
||||||
|
|
||||||
|
pub fn findCharImagePos(self: Self, c: u8) V2 {
|
||||||
|
var result = V2.zero;
|
||||||
|
|
||||||
|
var i: i32 = 0;
|
||||||
|
var j: i32 = 0;
|
||||||
|
switch (c) {
|
||||||
|
' ' => {
|
||||||
|
i = 15;
|
||||||
|
j = 1;
|
||||||
|
},
|
||||||
|
'(' => {
|
||||||
|
i = 7;
|
||||||
|
j = 2;
|
||||||
|
},
|
||||||
|
')' => {
|
||||||
|
i = 8;
|
||||||
|
j = 2;
|
||||||
|
},
|
||||||
|
',' => {
|
||||||
|
i = 11;
|
||||||
|
j = 2;
|
||||||
|
},
|
||||||
|
'-' => {
|
||||||
|
i = 12;
|
||||||
|
j = 2;
|
||||||
|
},
|
||||||
|
'.' => {
|
||||||
|
i = 13;
|
||||||
|
j = 2;
|
||||||
|
},
|
||||||
|
'0' => {
|
||||||
|
i = 15;
|
||||||
|
j = 2;
|
||||||
|
},
|
||||||
|
'1' => {
|
||||||
|
i = 0;
|
||||||
|
j = 3;
|
||||||
|
},
|
||||||
|
'2' => {
|
||||||
|
i = 1;
|
||||||
|
j = 3;
|
||||||
|
},
|
||||||
|
'3' => {
|
||||||
|
i = 2;
|
||||||
|
j = 3;
|
||||||
|
},
|
||||||
|
'4' => {
|
||||||
|
i = 3;
|
||||||
|
j = 3;
|
||||||
|
},
|
||||||
|
'5' => {
|
||||||
|
i = 4;
|
||||||
|
j = 3;
|
||||||
|
},
|
||||||
|
'6' => {
|
||||||
|
i = 5;
|
||||||
|
j = 3;
|
||||||
|
},
|
||||||
|
'7' => {
|
||||||
|
i = 6;
|
||||||
|
j = 3;
|
||||||
|
},
|
||||||
|
'8' => {
|
||||||
|
i = 7;
|
||||||
|
j = 3;
|
||||||
|
},
|
||||||
|
'9' => {
|
||||||
|
i = 8;
|
||||||
|
j = 3;
|
||||||
|
},
|
||||||
|
':' => {
|
||||||
|
i = 9;
|
||||||
|
j = 3;
|
||||||
|
},
|
||||||
|
'V' => {
|
||||||
|
i = 5;
|
||||||
|
j = 5;
|
||||||
|
},
|
||||||
|
'a' => {
|
||||||
|
i = 1;
|
||||||
|
j = 6;
|
||||||
|
},
|
||||||
|
'b' => {
|
||||||
|
i = 2;
|
||||||
|
j = 6;
|
||||||
|
},
|
||||||
|
'c' => {
|
||||||
|
i = 3;
|
||||||
|
j = 6;
|
||||||
|
},
|
||||||
|
'd' => {
|
||||||
|
i = 4;
|
||||||
|
j = 6;
|
||||||
|
},
|
||||||
|
'e' => {
|
||||||
|
i = 5;
|
||||||
|
j = 6;
|
||||||
|
},
|
||||||
|
'f' => {
|
||||||
|
i = 6;
|
||||||
|
j = 6;
|
||||||
|
},
|
||||||
|
'g' => {
|
||||||
|
i = 7;
|
||||||
|
j = 6;
|
||||||
|
},
|
||||||
|
'h' => {
|
||||||
|
i = 8;
|
||||||
|
j = 6;
|
||||||
|
},
|
||||||
|
'i' => {
|
||||||
|
i = 9;
|
||||||
|
j = 6;
|
||||||
|
},
|
||||||
|
'j' => {
|
||||||
|
i = 10;
|
||||||
|
j = 6;
|
||||||
|
},
|
||||||
|
'k' => {
|
||||||
|
i = 11;
|
||||||
|
j = 6;
|
||||||
|
},
|
||||||
|
'l' => {
|
||||||
|
i = 12;
|
||||||
|
j = 6;
|
||||||
|
},
|
||||||
|
'm' => {
|
||||||
|
i = 13;
|
||||||
|
j = 6;
|
||||||
|
},
|
||||||
|
'n' => {
|
||||||
|
i = 14;
|
||||||
|
j = 6;
|
||||||
|
},
|
||||||
|
'o' => {
|
||||||
|
i = 15;
|
||||||
|
j = 6;
|
||||||
|
},
|
||||||
|
'p' => {
|
||||||
|
i = 0;
|
||||||
|
j = 7;
|
||||||
|
},
|
||||||
|
'q' => {
|
||||||
|
i = 1;
|
||||||
|
j = 7;
|
||||||
|
},
|
||||||
|
'r' => {
|
||||||
|
i = 2;
|
||||||
|
j = 7;
|
||||||
|
},
|
||||||
|
's' => {
|
||||||
|
i = 3;
|
||||||
|
j = 7;
|
||||||
|
},
|
||||||
|
't' => {
|
||||||
|
i = 4;
|
||||||
|
j = 7;
|
||||||
|
},
|
||||||
|
'u' => {
|
||||||
|
i = 5;
|
||||||
|
j = 7;
|
||||||
|
},
|
||||||
|
'v' => {
|
||||||
|
i = 6;
|
||||||
|
j = 7;
|
||||||
|
},
|
||||||
|
'w' => {
|
||||||
|
i = 7;
|
||||||
|
j = 7;
|
||||||
|
},
|
||||||
|
'x' => {
|
||||||
|
i = 8;
|
||||||
|
j = 7;
|
||||||
|
},
|
||||||
|
'y' => {
|
||||||
|
i = 9;
|
||||||
|
j = 7;
|
||||||
|
},
|
||||||
|
'z' => {
|
||||||
|
i = 10;
|
||||||
|
j = 7;
|
||||||
|
},
|
||||||
|
else => {
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
result.x = @floatFromInt(i * self.glyph_width);
|
||||||
|
result.y = @floatFromInt(j * self.glyph_height);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
width: i32,
|
||||||
|
height: i32,
|
||||||
|
stride: i32,
|
||||||
|
components: i32,
|
||||||
|
data: []u8,
|
||||||
+64
@@ -0,0 +1,64 @@
|
|||||||
|
const std = @import("std");
|
||||||
|
const V2 = @This();
|
||||||
|
|
||||||
|
x: f32,
|
||||||
|
y: f32,
|
||||||
|
|
||||||
|
pub const max = V2{ .x = std.math.floatMax(f32), .y = std.math.floatMax(f32) };
|
||||||
|
pub const zero = V2{ .x = 0.0, .y = 0.0 };
|
||||||
|
|
||||||
|
pub fn init(x: f32, y: f32) V2 {
|
||||||
|
return .{
|
||||||
|
.x = x,
|
||||||
|
.y = y,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn initI32(x: i32, y: i32) V2 {
|
||||||
|
return .{
|
||||||
|
.x = @floatFromInt(x),
|
||||||
|
.y = @floatFromInt(y),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn initUSize(x: usize, y: usize) V2 {
|
||||||
|
return .{
|
||||||
|
.x = @floatFromInt(x),
|
||||||
|
.y = @floatFromInt(y),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn add(self: V2, other: V2) V2 {
|
||||||
|
return .{
|
||||||
|
.x = self.x + other.x,
|
||||||
|
.y = self.y + other.y,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn sub(self: V2, other: V2) V2 {
|
||||||
|
return .{
|
||||||
|
.x = self.x - other.x,
|
||||||
|
.y = self.y - other.y,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn mul(self: V2, s: f32) V2 {
|
||||||
|
return .{
|
||||||
|
.x = self.x * s,
|
||||||
|
.y = self.y * s,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn inner(self: V2, other: V2) f32 {
|
||||||
|
const result = self.x * other.x + self.y * other.y;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn hadamard(self: V2, other: V2) V2 {
|
||||||
|
var result = V2.zero;
|
||||||
|
|
||||||
|
result.x = self.x * other.x;
|
||||||
|
result.y = self.y * other.y;
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
+2
-2
@@ -769,7 +769,7 @@ const wl_seat_listener: c.wl_seat_listener = .{
|
|||||||
.name = wlSeatHandleName,
|
.name = wlSeatHandleName,
|
||||||
};
|
};
|
||||||
|
|
||||||
fn registry_handle_global(
|
fn registryHandleGlobal(
|
||||||
data: ?*anyopaque,
|
data: ?*anyopaque,
|
||||||
registry: ?*c.wl_registry,
|
registry: ?*c.wl_registry,
|
||||||
name: u32,
|
name: u32,
|
||||||
@@ -807,7 +807,7 @@ fn registryHandleGlobalRemove(
|
|||||||
|
|
||||||
|
|
||||||
const registry_listener: c.wl_registry_listener = .{
|
const registry_listener: c.wl_registry_listener = .{
|
||||||
.global = registry_handle_global,
|
.global = registryHandleGlobal,
|
||||||
.global_remove = registryHandleGlobalRemove,
|
.global_remove = registryHandleGlobalRemove,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
+16
-274
@@ -4,72 +4,12 @@ const builtin = @import("builtin");
|
|||||||
|
|
||||||
pub const platform = @import("platform.zig");
|
pub const platform = @import("platform.zig");
|
||||||
|
|
||||||
|
const V2 = @import("V2.zig");
|
||||||
|
const Image = @import("Image.zig");
|
||||||
|
const Font = @import("Font.zig");
|
||||||
|
|
||||||
const TILE_SIZE = 64;
|
const TILE_SIZE = 64;
|
||||||
|
|
||||||
const V2 = struct {
|
|
||||||
x: f32,
|
|
||||||
y: f32,
|
|
||||||
|
|
||||||
const max = V2{ .x = std.math.floatMax(f32), .y = std.math.floatMax(f32) };
|
|
||||||
const zero = V2{ .x = 0.0, .y = 0.0 };
|
|
||||||
|
|
||||||
fn init(x: f32, y: f32) V2 {
|
|
||||||
return .{
|
|
||||||
.x = x,
|
|
||||||
.y = y,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
fn initI32(x: i32, y: i32) V2 {
|
|
||||||
return .{
|
|
||||||
.x = @floatFromInt(x),
|
|
||||||
.y = @floatFromInt(y),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
fn initUSize(x: usize, y: usize) V2 {
|
|
||||||
return .{
|
|
||||||
.x = @floatFromInt(x),
|
|
||||||
.y = @floatFromInt(y),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
fn add(self: V2, other: V2) V2 {
|
|
||||||
return .{
|
|
||||||
.x = self.x + other.x,
|
|
||||||
.y = self.y + other.y,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
fn sub(self: V2, other: V2) V2 {
|
|
||||||
return .{
|
|
||||||
.x = self.x - other.x,
|
|
||||||
.y = self.y - other.y,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
fn mul(self: V2, s: f32) V2 {
|
|
||||||
return .{
|
|
||||||
.x = self.x * s,
|
|
||||||
.y = self.y * s,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
fn inner(self: V2, other: V2) f32 {
|
|
||||||
const result = self.x * other.x + self.y * other.y;
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
fn hadamard(self: V2, other: V2) V2 {
|
|
||||||
var result = V2.zero;
|
|
||||||
|
|
||||||
result.x = self.x * other.x;
|
|
||||||
result.y = self.y * other.y;
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const Rect = struct {
|
const Rect = struct {
|
||||||
pos: V2,
|
pos: V2,
|
||||||
size: V2,
|
size: V2,
|
||||||
@@ -86,14 +26,6 @@ const Camera = struct {
|
|||||||
offset: V2,
|
offset: V2,
|
||||||
};
|
};
|
||||||
|
|
||||||
const Image = struct {
|
|
||||||
width: i32,
|
|
||||||
height: i32,
|
|
||||||
stride: i32,
|
|
||||||
components: i32,
|
|
||||||
data: []u8,
|
|
||||||
};
|
|
||||||
|
|
||||||
const BoardTile = struct {
|
const BoardTile = struct {
|
||||||
blocked: bool,
|
blocked: bool,
|
||||||
taken: bool,
|
taken: bool,
|
||||||
@@ -204,6 +136,7 @@ const State = struct {
|
|||||||
mouse_pos: V2,
|
mouse_pos: V2,
|
||||||
camera: Camera,
|
camera: Camera,
|
||||||
font_image: Image,
|
font_image: Image,
|
||||||
|
font: Font,
|
||||||
draw_bounding_rects: bool,
|
draw_bounding_rects: bool,
|
||||||
grabbed_brick_index: ?usize,
|
grabbed_brick_index: ?usize,
|
||||||
bricks: [8]Brick,
|
bricks: [8]Brick,
|
||||||
@@ -467,9 +400,9 @@ fn drawImage(buffer: platform.OffscreenBuffer, image: Image, pos: V2, scale: f32
|
|||||||
const image_idx: usize = @intCast(new_y * image.stride + new_x);
|
const image_idx: usize = @intCast(new_y * image.stride + new_x);
|
||||||
const image_pixel: [*]u8 = image.data.ptr + image_idx;
|
const image_pixel: [*]u8 = image.data.ptr + image_idx;
|
||||||
var image_alpha: u32 = 0xFF;
|
var image_alpha: u32 = 0xFF;
|
||||||
const image_red: u32 = image_pixel[0];
|
const image_red: u32 = image_pixel[0];
|
||||||
const image_green: u32 = image_pixel[1];
|
const image_green: u32 = image_pixel[1];
|
||||||
const image_blue: u32 = image_pixel[2];
|
const image_blue: u32 = image_pixel[2];
|
||||||
if (image.components > 3) {
|
if (image.components > 3) {
|
||||||
image_alpha = image_pixel[3];
|
image_alpha = image_pixel[3];
|
||||||
}
|
}
|
||||||
@@ -494,209 +427,14 @@ fn drawImage(buffer: platform.OffscreenBuffer, image: Image, pos: V2, scale: f32
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn drawString(buffer: platform.OffscreenBuffer, font: Font, pos: V2, str: []const u8) void {
|
||||||
fn indexFont(font: Image, c: u8) V2 {
|
const image = font.image;
|
||||||
var result = V2.zero;
|
|
||||||
|
|
||||||
_ = font;
|
|
||||||
|
|
||||||
var i: i32 = 0;
|
|
||||||
var j: i32 = 0;
|
|
||||||
switch (c) {
|
|
||||||
' ' => {
|
|
||||||
i = 15;
|
|
||||||
j = 1;
|
|
||||||
},
|
|
||||||
'(' => {
|
|
||||||
i = 7;
|
|
||||||
j = 2;
|
|
||||||
},
|
|
||||||
')' => {
|
|
||||||
i = 8;
|
|
||||||
j = 2;
|
|
||||||
},
|
|
||||||
',' => {
|
|
||||||
i = 11;
|
|
||||||
j = 2;
|
|
||||||
},
|
|
||||||
'-' => {
|
|
||||||
i = 12;
|
|
||||||
j = 2;
|
|
||||||
},
|
|
||||||
'.' => {
|
|
||||||
i = 13;
|
|
||||||
j = 2;
|
|
||||||
},
|
|
||||||
'0' => {
|
|
||||||
i = 15;
|
|
||||||
j = 2;
|
|
||||||
},
|
|
||||||
'1' => {
|
|
||||||
i = 0;
|
|
||||||
j = 3;
|
|
||||||
},
|
|
||||||
'2' => {
|
|
||||||
i = 1;
|
|
||||||
j = 3;
|
|
||||||
},
|
|
||||||
'3' => {
|
|
||||||
i = 2;
|
|
||||||
j = 3;
|
|
||||||
},
|
|
||||||
'4' => {
|
|
||||||
i = 3;
|
|
||||||
j = 3;
|
|
||||||
},
|
|
||||||
'5' => {
|
|
||||||
i = 4;
|
|
||||||
j = 3;
|
|
||||||
},
|
|
||||||
'6' => {
|
|
||||||
i = 5;
|
|
||||||
j = 3;
|
|
||||||
},
|
|
||||||
'7' => {
|
|
||||||
i = 6;
|
|
||||||
j = 3;
|
|
||||||
},
|
|
||||||
'8' => {
|
|
||||||
i = 7;
|
|
||||||
j = 3;
|
|
||||||
},
|
|
||||||
'9' => {
|
|
||||||
i = 8;
|
|
||||||
j = 3;
|
|
||||||
},
|
|
||||||
':' => {
|
|
||||||
i = 9;
|
|
||||||
j = 3;
|
|
||||||
},
|
|
||||||
'V' => {
|
|
||||||
i = 5;
|
|
||||||
j = 5;
|
|
||||||
},
|
|
||||||
'a' => {
|
|
||||||
i = 1;
|
|
||||||
j = 6;
|
|
||||||
},
|
|
||||||
'b' => {
|
|
||||||
i = 2;
|
|
||||||
j = 6;
|
|
||||||
},
|
|
||||||
'c' => {
|
|
||||||
i = 3;
|
|
||||||
j = 6;
|
|
||||||
},
|
|
||||||
'd' => {
|
|
||||||
i = 4;
|
|
||||||
j = 6;
|
|
||||||
},
|
|
||||||
'e' => {
|
|
||||||
i = 5;
|
|
||||||
j = 6;
|
|
||||||
},
|
|
||||||
'f' => {
|
|
||||||
i = 6;
|
|
||||||
j = 6;
|
|
||||||
},
|
|
||||||
'g' => {
|
|
||||||
i = 7;
|
|
||||||
j = 6;
|
|
||||||
},
|
|
||||||
'h' => {
|
|
||||||
i = 8;
|
|
||||||
j = 6;
|
|
||||||
},
|
|
||||||
'i' => {
|
|
||||||
i = 9;
|
|
||||||
j = 6;
|
|
||||||
},
|
|
||||||
'j' => {
|
|
||||||
i = 10;
|
|
||||||
j = 6;
|
|
||||||
},
|
|
||||||
'k' => {
|
|
||||||
i = 11;
|
|
||||||
j = 6;
|
|
||||||
},
|
|
||||||
'l' => {
|
|
||||||
i = 12;
|
|
||||||
j = 6;
|
|
||||||
},
|
|
||||||
'm' => {
|
|
||||||
i = 13;
|
|
||||||
j = 6;
|
|
||||||
},
|
|
||||||
'n' => {
|
|
||||||
i = 14;
|
|
||||||
j = 6;
|
|
||||||
},
|
|
||||||
'o' => {
|
|
||||||
i = 15;
|
|
||||||
j = 6;
|
|
||||||
},
|
|
||||||
'p' => {
|
|
||||||
i = 0;
|
|
||||||
j = 7;
|
|
||||||
},
|
|
||||||
'q' => {
|
|
||||||
i = 1;
|
|
||||||
j = 7;
|
|
||||||
},
|
|
||||||
'r' => {
|
|
||||||
i = 2;
|
|
||||||
j = 7;
|
|
||||||
},
|
|
||||||
's' => {
|
|
||||||
i = 3;
|
|
||||||
j = 7;
|
|
||||||
},
|
|
||||||
't' => {
|
|
||||||
i = 4;
|
|
||||||
j = 7;
|
|
||||||
},
|
|
||||||
'u' => {
|
|
||||||
i = 5;
|
|
||||||
j = 7;
|
|
||||||
},
|
|
||||||
'v' => {
|
|
||||||
i = 6;
|
|
||||||
j = 7;
|
|
||||||
},
|
|
||||||
'w' => {
|
|
||||||
i = 7;
|
|
||||||
j = 7;
|
|
||||||
},
|
|
||||||
'x' => {
|
|
||||||
i = 8;
|
|
||||||
j = 7;
|
|
||||||
},
|
|
||||||
'y' => {
|
|
||||||
i = 9;
|
|
||||||
j = 7;
|
|
||||||
},
|
|
||||||
'z' => {
|
|
||||||
i = 10;
|
|
||||||
j = 7;
|
|
||||||
},
|
|
||||||
else => {
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
result.x = @floatFromInt(i * 32);
|
|
||||||
result.y = @floatFromInt(j * 32);
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
fn drawString(buffer: platform.OffscreenBuffer, image: Image, pos: V2, str: []const u8) void {
|
|
||||||
var current_pos = pos;
|
var current_pos = pos;
|
||||||
const font_size = 32;
|
const font_size = 32;
|
||||||
const scale = 0.5;
|
const scale = 0.5;
|
||||||
const font_width_scaled = scale * font_size;
|
const font_width_scaled = scale * font_size;
|
||||||
for (str) |c| {
|
for (str) |c| {
|
||||||
const char_image_pos = indexFont(image, c);
|
const char_image_pos = font.findCharImagePos(c);
|
||||||
|
|
||||||
const pos_x: i32 = @intFromFloat(char_image_pos.x);
|
const pos_x: i32 = @intFromFloat(char_image_pos.x);
|
||||||
const pos_y: i32 = @intFromFloat(char_image_pos.y);
|
const pos_y: i32 = @intFromFloat(char_image_pos.y);
|
||||||
@@ -768,7 +506,11 @@ pub fn updateAndRender(memory: *platform.AppMemory, buffer: platform.OffscreenBu
|
|||||||
|
|
||||||
const font_image = loadPng("assets/font.png");
|
const font_image = loadPng("assets/font.png");
|
||||||
if (font_image) |img| {
|
if (font_image) |img| {
|
||||||
state.font_image = img;
|
state.font = .{
|
||||||
|
.glyph_width = 32,
|
||||||
|
.glyph_height = 32,
|
||||||
|
.image = img,
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
const indices = [4][4]?BoardIndex{
|
const indices = [4][4]?BoardIndex{
|
||||||
@@ -1073,7 +815,7 @@ pub fn updateAndRender(memory: *platform.AppMemory, buffer: platform.OffscreenBu
|
|||||||
drawRect(buffer, camera_pos, board.tile_size, 0xFFFFFFFF, 2);
|
drawRect(buffer, camera_pos, board.tile_size, 0xFFFFFFFF, 2);
|
||||||
|
|
||||||
const string_camera_pos = string_pos.add(state.camera.pos);
|
const string_camera_pos = string_pos.add(state.camera.pos);
|
||||||
drawString(buffer, state.font_image, string_camera_pos, tile.label);
|
drawString(buffer, state.font, string_camera_pos, tile.label);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user