paint: sculpt layer fixes
This commit is contained in:
@@ -602,8 +602,8 @@ void render_path_raytrace_init();
|
||||
void render_path_raytrace_raytrace_init(char *shader_name, bool build);
|
||||
void render_path_raytrace_draw(bool use_live_layer);
|
||||
node_shader_context_t *sculpt_make_sculpt_run(material_t *data, material_context_t *matcon);
|
||||
void sculpt_make_mesh_run(node_shader_t *kong, slot_layer_t *l);
|
||||
void sculpt_import_mesh_pack_to_texture(mesh_data_t *mesh, slot_layer_t *l);
|
||||
void sculpt_make_mesh_run(node_shader_t *kong, slot_layer_t_array_t *sculpt_layers, i32_array_t *sculpt_indices);
|
||||
void sculpt_import_mesh_pack_to_texture(mesh_data_t *mesh, gpu_texture_t *target);
|
||||
void sculpt_init_sculpt_texture(slot_layer_t *l, mesh_data_t *md);
|
||||
void sculpt_init();
|
||||
void sculpt_layers_create_sculpt_layer();
|
||||
|
||||
@@ -110,6 +110,7 @@ void import_mesh_finish_import(void *_) {
|
||||
render_path_raytrace_ready = false;
|
||||
g_context->paint_body = NULL;
|
||||
tab_meshes_reset_preview_map();
|
||||
base_update_workflow();
|
||||
|
||||
if (import_mesh_needs_unwrap) {
|
||||
import_mesh_needs_unwrap = false;
|
||||
|
||||
@@ -60,6 +60,19 @@ node_shader_context_t *make_depth_run(material_t *data, material_context_t *matc
|
||||
|
||||
node_shader_write_vert(kong, "output.pos = constants.VP * float4(output.wposition.xyz, 1.0);");
|
||||
|
||||
// {
|
||||
// slot_layer_t_array_t *sculpt_layers = any_array_create_from_raw((void *[]){}, 0);
|
||||
// i32_array_t *sculpt_indices = i32_array_create(0);
|
||||
// for (i32 i = 0; i < project_layers->length; ++i) {
|
||||
// slot_layer_t *l = project_layers->buffer[i];
|
||||
// if (l->texpaint_sculpt != NULL && slot_layer_is_visible(l)) {
|
||||
// any_array_push(sculpt_layers, l);
|
||||
// i32_array_push(sculpt_indices, i);
|
||||
// }
|
||||
// }
|
||||
// sculpt_make_mesh_run(kong, sculpt_layers, sculpt_indices);
|
||||
// }
|
||||
|
||||
con_depth->data->color_writes_red = u8_array_create_from_raw(
|
||||
(u8[]){
|
||||
false,
|
||||
|
||||
@@ -162,11 +162,17 @@ node_shader_context_t *make_mesh_run(material_t *data, i32 layer_pass) {
|
||||
kong->frag_n = true;
|
||||
node_shader_add_function(kong, str_pack_float_int16);
|
||||
|
||||
for (i32 i = 0; i < project_layers->length; ++i) {
|
||||
slot_layer_t *l = project_layers->buffer[i];
|
||||
if (l->texpaint_sculpt != NULL) {
|
||||
sculpt_make_mesh_run(kong, l);
|
||||
{
|
||||
slot_layer_t_array_t *sculpt_layers = any_array_create_from_raw((void *[]){}, 0);
|
||||
i32_array_t *sculpt_indices = i32_array_create(0);
|
||||
for (i32 i = 0; i < project_layers->length; ++i) {
|
||||
slot_layer_t *l = project_layers->buffer[i];
|
||||
if (l->texpaint_sculpt != NULL && slot_layer_is_visible(l)) {
|
||||
any_array_push(sculpt_layers, l);
|
||||
i32_array_push(sculpt_indices, i);
|
||||
}
|
||||
}
|
||||
sculpt_make_mesh_run(kong, sculpt_layers, sculpt_indices);
|
||||
}
|
||||
|
||||
if (g_context->colorid_viewport_mask && g_context->tool != TOOL_TYPE_COLORID) {
|
||||
@@ -371,8 +377,8 @@ node_shader_context_t *make_mesh_run(material_t *data, i32 layer_pass) {
|
||||
node_shader_write_frag(kong, "basecol = texpaint_sample.rgb * texpaint_opac;");
|
||||
}
|
||||
else {
|
||||
node_shader_write_frag(kong, string("basecol = %s;",
|
||||
make_material_blend_mode(kong, slot_layer_get_blending(l), "basecol", "texpaint_sample.rgb", "texpaint_opac")));
|
||||
node_shader_write_frag(kong, string("basecol = %s;", make_material_blend_mode(kong, slot_layer_get_blending(l), "basecol",
|
||||
"texpaint_sample.rgb", "texpaint_opac")));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -584,8 +584,48 @@ node_shader_context_t *make_paint_run(material_t *data, material_context_t *matc
|
||||
}
|
||||
|
||||
parser_material_finalize(con_paint);
|
||||
parser_material_triplanar = false;
|
||||
parser_material_sample_keep_aspect = false;
|
||||
parser_material_triplanar = false;
|
||||
parser_material_sample_keep_aspect = false;
|
||||
|
||||
{
|
||||
slot_layer_t_array_t *sculpt_layers = any_array_create_from_raw((void *[]){}, 0);
|
||||
i32_array_t *sculpt_indices = i32_array_create(0);
|
||||
for (i32 i = 0; i < project_layers->length; ++i) {
|
||||
slot_layer_t *l = project_layers->buffer[i];
|
||||
if (l->texpaint_sculpt != NULL && slot_layer_is_visible(l)) {
|
||||
any_array_push(sculpt_layers, l);
|
||||
i32_array_push(sculpt_indices, i);
|
||||
}
|
||||
}
|
||||
i32 scount = sculpt_layers->length;
|
||||
if (scount > 0) {
|
||||
i32 idx0 = sculpt_indices->buffer[0];
|
||||
node_shader_add_constant(kong, string("texpaint_sculpt_size%d: float2", idx0), string("_size(_texpaint_sculpt%d)", idx0));
|
||||
for (i32 i = 0; i < scount; ++i) {
|
||||
i32 idx = sculpt_indices->buffer[i];
|
||||
node_shader_add_texture(kong, string("texpaint_sculpt%d", idx), string("_texpaint_sculpt%d", idx));
|
||||
}
|
||||
if (scount > 1) {
|
||||
node_shader_add_texture(kong, "texpaint_sculpt_base", "_texpaint_sculpt_base");
|
||||
}
|
||||
|
||||
node_shader_write_attrib_vert(kong, string("var sculpt_uv_paint: uint2 = uint2(uint(float(vertex_id()) %% constants.texpaint_sculpt_size%d.x), "
|
||||
"uint(float(vertex_id()) / constants.texpaint_sculpt_size%d.y));",
|
||||
idx0, idx0));
|
||||
|
||||
node_shader_write_attrib_vert(kong, string("var sculpt_pos_paint: float4 = texpaint_sculpt%d[sculpt_uv_paint];", idx0));
|
||||
for (i32 i = 1; i < scount; ++i) {
|
||||
i32 idx = sculpt_indices->buffer[i];
|
||||
node_shader_write_attrib_vert(
|
||||
kong, string("sculpt_pos_paint = sculpt_pos_paint + texpaint_sculpt%d[sculpt_uv_paint] - texpaint_sculpt_base[sculpt_uv_paint];", idx));
|
||||
}
|
||||
node_shader_write_attrib_vert(kong, "output.ndc = constants.WVP * float4(sculpt_pos_paint.xyz, 1.0);");
|
||||
if (kong->frag_wposition) {
|
||||
node_shader_write_attrib_vert(kong, "output.wposition = (constants.W * float4(sculpt_pos_paint.xyz, 1.0)).xyz;");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
con_paint->data->shader_from_source = true;
|
||||
gpu_create_shaders_from_kong(node_shader_get(kong), &con_paint->data->vertex_shader, &con_paint->data->fragment_shader,
|
||||
&con_paint->data->_->vertex_shader_size, &con_paint->data->_->fragment_shader_size);
|
||||
|
||||
+87
-26
@@ -1,7 +1,7 @@
|
||||
|
||||
#include "global.h"
|
||||
|
||||
void sculpt_import_mesh_pack_to_texture(mesh_data_t *mesh, slot_layer_t *l) {
|
||||
void sculpt_import_mesh_pack_to_texture(mesh_data_t *mesh, gpu_texture_t *target) {
|
||||
buffer_t *b = buffer_create(config_get_texture_res_x() * config_get_texture_res_y() * 4 * 4);
|
||||
for (i32 i = 0; i < math_floor(mesh->index_array->length); ++i) {
|
||||
i32 index = mesh->index_array->buffer[i];
|
||||
@@ -24,7 +24,7 @@ void sculpt_import_mesh_pack_to_texture(mesh_data_t *mesh, slot_layer_t *l) {
|
||||
}
|
||||
|
||||
gpu_texture_t *imgmesh = gpu_create_texture_from_bytes(b, config_get_texture_res_x(), config_get_texture_res_y(), GPU_TEXTURE_FORMAT_RGBA128);
|
||||
draw_begin(l->texpaint_sculpt, false, 0);
|
||||
draw_begin(target, false, 0);
|
||||
draw_set_pipeline(pipes_copy128);
|
||||
draw_scaled_image(imgmesh, 0, 0, config_get_texture_res_x(), config_get_texture_res_y());
|
||||
draw_set_pipeline(NULL);
|
||||
@@ -211,38 +211,73 @@ node_shader_context_t *sculpt_make_sculpt_run(material_t *data, material_context
|
||||
return con_paint;
|
||||
}
|
||||
|
||||
void sculpt_make_mesh_run(node_shader_t *kong, slot_layer_t *l) {
|
||||
void sculpt_make_mesh_run(node_shader_t *kong, slot_layer_t_array_t *sculpt_layers, i32_array_t *sculpt_indices) {
|
||||
i32 count = sculpt_layers->length;
|
||||
if (count == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
i32 idx0 = sculpt_indices->buffer[0];
|
||||
|
||||
node_shader_add_constant(kong, "WVP: float4x4", "_world_view_proj_matrix");
|
||||
i32 lid = array_index_of(project_layers, l);
|
||||
node_shader_add_texture(kong, "texpaint_sculpt", string("_texpaint_sculpt%s", i32_to_string(lid)));
|
||||
node_shader_add_constant(kong, "texpaint_sculpt_size: float2", string("_size(_texpaint_sculpt%s)", i32_to_string(lid)));
|
||||
// node_shader_write_vert(kong, "var meshpos: float3 = sample_lod(texpaint_sculpt, sampler_linear, uint2(vertex_id() % constants.texpaint_sculpt_size.x,
|
||||
// vertex_id() / constants.texpaint_sculpt_size.y), 0.0).xyz;");
|
||||
node_shader_write_vert(kong, "var meshpos: float4 = texpaint_sculpt[uint2(uint(float(vertex_id()) % constants.texpaint_sculpt_size.x), "
|
||||
"uint(float(vertex_id()) / constants.texpaint_sculpt_size.y))];");
|
||||
// + input.pos.xyz * 0.000001
|
||||
node_shader_write_vert(kong, "output.pos = constants.WVP * float4(meshpos.xyz, 1.0);");
|
||||
kong->frag_n = false;
|
||||
node_shader_add_constant(kong, "N: float3x3", "_normal_matrix");
|
||||
node_shader_add_out(kong, "wnormal: float3");
|
||||
kong->frag_n = false;
|
||||
|
||||
node_shader_add_constant(kong, string("texpaint_sculpt_size%d: float2", idx0), string("_size(_texpaint_sculpt%d)", idx0));
|
||||
|
||||
for (i32 i = 0; i < count; ++i) {
|
||||
i32 idx = sculpt_indices->buffer[i];
|
||||
node_shader_add_texture(kong, string("texpaint_sculpt%d", idx), string("_texpaint_sculpt%d", idx));
|
||||
}
|
||||
|
||||
if (count > 1) {
|
||||
node_shader_add_texture(kong, "texpaint_sculpt_base", "_texpaint_sculpt_base");
|
||||
}
|
||||
|
||||
// Position
|
||||
node_shader_write_vert(kong, string("var sculpt_uv: uint2 = uint2(uint(float(vertex_id()) %% constants.texpaint_sculpt_size%d.x), "
|
||||
"uint(float(vertex_id()) / constants.texpaint_sculpt_size%d.y));",
|
||||
idx0, idx0));
|
||||
node_shader_write_vert(kong, string("var texpaint_sculpt_sample: float4 = texpaint_sculpt%d[sculpt_uv];", idx0));
|
||||
node_shader_write_vert(kong, "var sculpt_pos: float3 = texpaint_sculpt_sample.xyz;");
|
||||
for (i32 i = 1; i < count; ++i) {
|
||||
i32 idx = sculpt_indices->buffer[i];
|
||||
node_shader_write_vert(kong, string("var texpaint_sculpt_sample_%d: float4 = texpaint_sculpt%d[sculpt_uv];", idx, idx));
|
||||
node_shader_write_vert(kong, string("var texpaint_sculpt_base_sample_%d: float4 = texpaint_sculpt_base[sculpt_uv];", idx));
|
||||
node_shader_write_vert(kong, string("sculpt_pos = sculpt_pos + texpaint_sculpt_sample_%d.xyz - texpaint_sculpt_base_sample_%d.xyz;", idx, idx));
|
||||
}
|
||||
node_shader_write_vert(kong, "output.pos = constants.WVP * float4(sculpt_pos, 1.0);");
|
||||
|
||||
// Normal
|
||||
node_shader_write_attrib_vert(kong, "var base_vertex0: float = float(vertex_id()) - (float(vertex_id()) % float(3));");
|
||||
node_shader_write_attrib_vert(kong, "var base_vertex1: float = base_vertex0 + 1.0;");
|
||||
node_shader_write_attrib_vert(kong, "var base_vertex2: float = base_vertex0 + 2.0;");
|
||||
// node_shader_write_attrib_vert(kong, "var meshpos0: float3 = sample_lod(texpaint_sculpt, sampler_linear, uint2(base_vertex0 %
|
||||
// constants.texpaint_sculpt_size.x, base_vertex0 / constants.texpaint_sculpt_size.y), 0.0).xyz;"); node_shader_write_attrib_vert(kong, "var meshpos1:
|
||||
// float3 = sample_lod(texpaint_sculpt, sampler_linear, uint2(base_vertex1 % constants.texpaint_sculpt_size.x, base_vertex1 /
|
||||
// constants.texpaint_sculpt_size.y), 0.0).xyz;"); node_shader_write_attrib_vert(kong, "var meshpos2: float3 = sample_lod(texpaint_sculpt, sampler_linear,
|
||||
// uint2(base_vertex2 % constants.texpaint_sculpt_size.x, base_vertex2 / constants.texpaint_sculpt_size.y), 0.0).xyz;");
|
||||
node_shader_write_attrib_vert(kong, "var meshpos0: float4 = texpaint_sculpt[uint2(uint(base_vertex0 % constants.texpaint_sculpt_size.x), uint(base_vertex0 "
|
||||
"/ constants.texpaint_sculpt_size.y))];");
|
||||
node_shader_write_attrib_vert(kong, "var meshpos1: float4 = texpaint_sculpt[uint2(uint(base_vertex1 % constants.texpaint_sculpt_size.x), uint(base_vertex1 "
|
||||
"/ constants.texpaint_sculpt_size.y))];");
|
||||
node_shader_write_attrib_vert(kong, "var meshpos2: float4 = texpaint_sculpt[uint2(uint(base_vertex2 % constants.texpaint_sculpt_size.x), uint(base_vertex2 "
|
||||
"/ constants.texpaint_sculpt_size.y))];");
|
||||
node_shader_write_attrib_vert(
|
||||
kong,
|
||||
string("var uv0: uint2 = uint2(uint(base_vertex0 %% constants.texpaint_sculpt_size%d.x), uint(base_vertex0 / constants.texpaint_sculpt_size%d.y));",
|
||||
idx0, idx0));
|
||||
node_shader_write_attrib_vert(
|
||||
kong,
|
||||
string("var uv1: uint2 = uint2(uint(base_vertex1 %% constants.texpaint_sculpt_size%d.x), uint(base_vertex1 / constants.texpaint_sculpt_size%d.y));",
|
||||
idx0, idx0));
|
||||
node_shader_write_attrib_vert(
|
||||
kong,
|
||||
string("var uv2: uint2 = uint2(uint(base_vertex2 %% constants.texpaint_sculpt_size%d.x), uint(base_vertex2 / constants.texpaint_sculpt_size%d.y));",
|
||||
idx0, idx0));
|
||||
|
||||
node_shader_write_attrib_vert(kong, string("var meshpos0: float4 = texpaint_sculpt%d[uv0];", idx0));
|
||||
node_shader_write_attrib_vert(kong, string("var meshpos1: float4 = texpaint_sculpt%d[uv1];", idx0));
|
||||
node_shader_write_attrib_vert(kong, string("var meshpos2: float4 = texpaint_sculpt%d[uv2];", idx0));
|
||||
for (i32 i = 1; i < count; ++i) {
|
||||
i32 idx = sculpt_indices->buffer[i];
|
||||
node_shader_write_attrib_vert(kong, string("meshpos0 = meshpos0 + texpaint_sculpt%d[uv0] - texpaint_sculpt_base[uv0];", idx));
|
||||
node_shader_write_attrib_vert(kong, string("meshpos1 = meshpos1 + texpaint_sculpt%d[uv1] - texpaint_sculpt_base[uv1];", idx));
|
||||
node_shader_write_attrib_vert(kong, string("meshpos2 = meshpos2 + texpaint_sculpt%d[uv2] - texpaint_sculpt_base[uv2];", idx));
|
||||
}
|
||||
|
||||
node_shader_write_attrib_vert(kong, "var meshnor: float3 = normalize(cross(meshpos2.xyz - meshpos1.xyz, meshpos0.xyz - meshpos1.xyz));");
|
||||
node_shader_write_attrib_vert(kong, "output.wnormal = constants.N * meshnor;");
|
||||
|
||||
node_shader_write_attrib_frag(kong, "var n: float3 = normalize(input.wnormal);");
|
||||
}
|
||||
|
||||
@@ -256,7 +291,29 @@ void sculpt_init_sculpt_texture(slot_layer_t *l, mesh_data_t *md) {
|
||||
t->format = "RGBA128";
|
||||
l->texpaint_sculpt = render_path_create_render_target(t)->_image;
|
||||
}
|
||||
sculpt_import_mesh_pack_to_texture(md, l);
|
||||
sculpt_import_mesh_pack_to_texture(md, l->texpaint_sculpt);
|
||||
|
||||
i32 sculpt_layer_count = 0;
|
||||
for (i32 i = 0; i < project_layers->length; ++i) {
|
||||
if (project_layers->buffer[i]->texpaint_sculpt != NULL) {
|
||||
sculpt_layer_count++;
|
||||
}
|
||||
}
|
||||
|
||||
if (any_map_get(render_path_render_targets, "texpaint_sculpt_base") == NULL) {
|
||||
render_target_t *t = render_target_create();
|
||||
t->name = "texpaint_sculpt_base";
|
||||
t->width = config_get_texture_res_x();
|
||||
t->height = config_get_texture_res_y();
|
||||
t->format = "RGBA128";
|
||||
render_path_create_render_target(t);
|
||||
}
|
||||
|
||||
if (sculpt_layer_count == 1) {
|
||||
render_path_set_target("texpaint_sculpt_base", NULL, NULL, GPU_CLEAR_NONE, 0, 0.0);
|
||||
render_path_bind_target(string("texpaint_sculpt%s", i32_to_string(id)), "tex");
|
||||
render_path_draw_shader("Scene/copy_pass/copyRGBA128_pass");
|
||||
}
|
||||
}
|
||||
|
||||
void sculpt_init() {
|
||||
@@ -296,6 +353,10 @@ void sculpt_init() {
|
||||
md = mesh_data_create(raw);
|
||||
mesh_object_set_data(g_context->paint_object, md);
|
||||
|
||||
if (g_context->merged_object != NULL) {
|
||||
util_mesh_merge(NULL);
|
||||
}
|
||||
|
||||
make_material_parse_paint_material(true);
|
||||
make_material_parse_mesh_material();
|
||||
|
||||
|
||||
@@ -433,6 +433,17 @@ void render_path_paint_commands_paint(bool dilation) {
|
||||
if (read_tc) {
|
||||
render_path_bind_target("gbuffer2", "gbuffer2");
|
||||
}
|
||||
i32 sculpt_layer_count = 0;
|
||||
for (i32 i = 0; i < project_layers->length; ++i) {
|
||||
slot_layer_t *sl = project_layers->buffer[i];
|
||||
if (sl->texpaint_sculpt != NULL && slot_layer_is_visible(sl)) {
|
||||
render_path_bind_target(string("texpaint_sculpt%d", sl->id), string("texpaint_sculpt%d", sl->id));
|
||||
sculpt_layer_count++;
|
||||
}
|
||||
}
|
||||
if (sculpt_layer_count > 1) {
|
||||
render_path_bind_target("texpaint_sculpt_base", "texpaint_sculpt_base");
|
||||
}
|
||||
object_t *bullet = scene_get_child(".Bullet");
|
||||
bool bullet_vis = bullet != NULL && bullet->visible;
|
||||
if (bullet != NULL) {
|
||||
@@ -703,8 +714,8 @@ void render_path_paint_commands_cursor() {
|
||||
return;
|
||||
}
|
||||
|
||||
f32 mx = g_context->paint_vec.x;
|
||||
f32 my = 1.0 - g_context->paint_vec.y;
|
||||
f32 mx = g_context->paint_vec.x;
|
||||
f32 my = 1.0 - g_context->paint_vec.y;
|
||||
f32 brush_nodes_radius = 1.0; // g_context->brush_nodes_radius; // Prevent cursor jumping constantly if randomness is used in brush nodes
|
||||
|
||||
if (context_is_decal() && !g_context->paint2d) {
|
||||
|
||||
@@ -1168,7 +1168,7 @@ void layers_update_fill_layers() {
|
||||
if (l->texpaint_sculpt != NULL) {
|
||||
i32 tid = l->id;
|
||||
i32 hid = history_undo_i - 1 < 0 ? g_config->undo_steps - 1 : history_undo_i - 1;
|
||||
sculpt_import_mesh_pack_to_texture(g_context->paint_object->data, l);
|
||||
sculpt_import_mesh_pack_to_texture(g_context->paint_object->data, l->texpaint_sculpt);
|
||||
render_path_set_target(string("texpaint_sculpt_undo%d", hid), NULL, NULL, GPU_CLEAR_NONE, 0, 0.0);
|
||||
render_path_bind_target(string("texpaint_sculpt%d", tid), "tex");
|
||||
render_path_draw_shader("Scene/copy_pass/copyRGBA128_pass");
|
||||
@@ -1248,7 +1248,7 @@ void layers_update_fill_layer(bool parse_paint) {
|
||||
if (g_context->layer->texpaint_sculpt != NULL) {
|
||||
i32 tid = g_context->layer->id;
|
||||
i32 hid = history_undo_i - 1 < 0 ? g_config->undo_steps - 1 : history_undo_i - 1;
|
||||
sculpt_import_mesh_pack_to_texture(g_context->paint_object->data, g_context->layer);
|
||||
sculpt_import_mesh_pack_to_texture(g_context->paint_object->data, g_context->layer->texpaint_sculpt);
|
||||
render_path_set_target(string("texpaint_sculpt_undo%d", hid), NULL, NULL, GPU_CLEAR_NONE, 0, 0.0);
|
||||
render_path_bind_target(string("texpaint_sculpt%d", tid), "tex");
|
||||
render_path_draw_shader("Scene/copy_pass/copyRGBA128_pass");
|
||||
|
||||
@@ -381,6 +381,10 @@ gpu_texture_t *uniforms_ext_tex_link(object_t *object, material_data_t *mat, cha
|
||||
i32 tid = parse_int(substring(link, string_length(link) - 1, string_length(link)));
|
||||
return tid < project_layers->length ? project_layers->buffer[tid]->texpaint_pack : NULL;
|
||||
}
|
||||
if (string_equals(link, "_texpaint_sculpt_base")) {
|
||||
render_target_t *rt = any_map_get(render_path_render_targets, "texpaint_sculpt_base");
|
||||
return rt != NULL ? rt->_image : NULL;
|
||||
}
|
||||
if (starts_with(link, "_texpaint_sculpt")) {
|
||||
i32 tid = parse_int(substring(link, string_length(link) - 1, string_length(link)));
|
||||
return tid < project_layers->length ? project_layers->buffer[tid]->texpaint_sculpt : NULL;
|
||||
|
||||
Reference in New Issue
Block a user