mirror of
https://github.com/Ttanasart-pt/Pixel-Composer.git
synced 2025-02-05 09:45:17 +01:00
[Zoom blur] Add step rendering mode.
This commit is contained in:
parent
0bb7d0ece7
commit
28c6e15a4a
9 changed files with 136 additions and 13 deletions
|
@ -268,6 +268,7 @@
|
||||||
{"name":"rotator","order":2,"path":"folders/widgets/rotator.yy",},
|
{"name":"rotator","order":2,"path":"folders/widgets/rotator.yy",},
|
||||||
{"name":"sliders","order":3,"path":"folders/widgets/sliders.yy",},
|
{"name":"sliders","order":3,"path":"folders/widgets/sliders.yy",},
|
||||||
{"name":"text","order":4,"path":"folders/widgets/text.yy",},
|
{"name":"text","order":4,"path":"folders/widgets/text.yy",},
|
||||||
|
{"name":"blur zoom","order":23,"path":"folders/nodes/data/filter/blur/blur zoom.yy",},
|
||||||
],
|
],
|
||||||
"ResourceOrderSettings":[
|
"ResourceOrderSettings":[
|
||||||
{"name":"ac_disappear","order":2,"path":"animcurves/ac_disappear/ac_disappear.yy",},
|
{"name":"ac_disappear","order":2,"path":"animcurves/ac_disappear/ac_disappear.yy",},
|
||||||
|
@ -769,7 +770,7 @@
|
||||||
{"name":"node_blur_shape","order":17,"path":"scripts/node_blur_shape/node_blur_shape.yy",},
|
{"name":"node_blur_shape","order":17,"path":"scripts/node_blur_shape/node_blur_shape.yy",},
|
||||||
{"name":"node_blur_simple","order":19,"path":"scripts/node_blur_simple/node_blur_simple.yy",},
|
{"name":"node_blur_simple","order":19,"path":"scripts/node_blur_simple/node_blur_simple.yy",},
|
||||||
{"name":"node_blur_slope","order":21,"path":"scripts/node_blur_slope/node_blur_slope.yy",},
|
{"name":"node_blur_slope","order":21,"path":"scripts/node_blur_slope/node_blur_slope.yy",},
|
||||||
{"name":"node_blur_zoom","order":23,"path":"scripts/node_blur_zoom/node_blur_zoom.yy",},
|
{"name":"node_blur_zoom","order":22,"path":"scripts/node_blur_zoom/node_blur_zoom.yy",},
|
||||||
{"name":"node_blur","order":4,"path":"scripts/node_blur/node_blur.yy",},
|
{"name":"node_blur","order":4,"path":"scripts/node_blur/node_blur.yy",},
|
||||||
{"name":"node_boolean","order":17,"path":"scripts/node_boolean/node_boolean.yy",},
|
{"name":"node_boolean","order":17,"path":"scripts/node_boolean/node_boolean.yy",},
|
||||||
{"name":"node_box_pattern","order":22,"path":"scripts/node_box_pattern/node_box_pattern.yy",},
|
{"name":"node_box_pattern","order":22,"path":"scripts/node_box_pattern/node_box_pattern.yy",},
|
||||||
|
@ -943,6 +944,7 @@
|
||||||
{"name":"node_lua_global","order":1,"path":"scripts/node_lua_global/node_lua_global.yy",},
|
{"name":"node_lua_global","order":1,"path":"scripts/node_lua_global/node_lua_global.yy",},
|
||||||
{"name":"node_lua_surface","order":2,"path":"scripts/node_lua_surface/node_lua_surface.yy",},
|
{"name":"node_lua_surface","order":2,"path":"scripts/node_lua_surface/node_lua_surface.yy",},
|
||||||
{"name":"node_math","order":2,"path":"scripts/node_math/node_math.yy",},
|
{"name":"node_math","order":2,"path":"scripts/node_math/node_math.yy",},
|
||||||
|
{"name":"sh_blur_slope","order":21,"path":"shaders/sh_blur_slope/sh_blur_slope.yy",},
|
||||||
{"name":"node_matrix_color_apply","order":7,"path":"scripts/node_matrix_color_apply/node_matrix_color_apply.yy",},
|
{"name":"node_matrix_color_apply","order":7,"path":"scripts/node_matrix_color_apply/node_matrix_color_apply.yy",},
|
||||||
{"name":"node_matrix_det","order":2,"path":"scripts/node_matrix_det/node_matrix_det.yy",},
|
{"name":"node_matrix_det","order":2,"path":"scripts/node_matrix_det/node_matrix_det.yy",},
|
||||||
{"name":"node_matrix_invert","order":3,"path":"scripts/node_matrix_invert/node_matrix_invert.yy",},
|
{"name":"node_matrix_invert","order":3,"path":"scripts/node_matrix_invert/node_matrix_invert.yy",},
|
||||||
|
@ -1521,8 +1523,6 @@
|
||||||
{"name":"sh_blur_radial","order":16,"path":"shaders/sh_blur_radial/sh_blur_radial.yy",},
|
{"name":"sh_blur_radial","order":16,"path":"shaders/sh_blur_radial/sh_blur_radial.yy",},
|
||||||
{"name":"sh_blur_shape","order":18,"path":"shaders/sh_blur_shape/sh_blur_shape.yy",},
|
{"name":"sh_blur_shape","order":18,"path":"shaders/sh_blur_shape/sh_blur_shape.yy",},
|
||||||
{"name":"sh_blur_simple","order":20,"path":"shaders/sh_blur_simple/sh_blur_simple.yy",},
|
{"name":"sh_blur_simple","order":20,"path":"shaders/sh_blur_simple/sh_blur_simple.yy",},
|
||||||
{"name":"sh_blur_slope","order":22,"path":"shaders/sh_blur_slope/sh_blur_slope.yy",},
|
|
||||||
{"name":"sh_blur_zoom","order":24,"path":"shaders/sh_blur_zoom/sh_blur_zoom.yy",},
|
|
||||||
{"name":"sh_box_pattern","order":23,"path":"shaders/sh_box_pattern/sh_box_pattern.yy",},
|
{"name":"sh_box_pattern","order":23,"path":"shaders/sh_box_pattern/sh_box_pattern.yy",},
|
||||||
{"name":"sh_brush_linear","order":47,"path":"shaders/sh_brush_linear/sh_brush_linear.yy",},
|
{"name":"sh_brush_linear","order":47,"path":"shaders/sh_brush_linear/sh_brush_linear.yy",},
|
||||||
{"name":"sh_brush_outline","order":7,"path":"shaders/sh_brush_outline/sh_brush_outline.yy",},
|
{"name":"sh_brush_outline","order":7,"path":"shaders/sh_brush_outline/sh_brush_outline.yy",},
|
||||||
|
@ -1894,6 +1894,7 @@
|
||||||
{"name":"s_node_3d_light_directional","order":18,"path":"sprites/s_node_3d_light_directional/s_node_3d_light_directional.yy",},
|
{"name":"s_node_3d_light_directional","order":18,"path":"sprites/s_node_3d_light_directional/s_node_3d_light_directional.yy",},
|
||||||
{"name":"s_node_3d_light_point","order":19,"path":"sprites/s_node_3d_light_point/s_node_3d_light_point.yy",},
|
{"name":"s_node_3d_light_point","order":19,"path":"sprites/s_node_3d_light_point/s_node_3d_light_point.yy",},
|
||||||
{"name":"s_node_3d_material","order":13,"path":"sprites/s_node_3d_material/s_node_3d_material.yy",},
|
{"name":"s_node_3d_material","order":13,"path":"sprites/s_node_3d_material/s_node_3d_material.yy",},
|
||||||
|
{"name":"sh_blur_zoom_step","order":1,"path":"shaders/sh_blur_zoom_step/sh_blur_zoom_step.yy",},
|
||||||
{"name":"s_node_3d_mesh_cone","order":9,"path":"sprites/s_node_3d_mesh_cone/s_node_3d_mesh_cone.yy",},
|
{"name":"s_node_3d_mesh_cone","order":9,"path":"sprites/s_node_3d_mesh_cone/s_node_3d_mesh_cone.yy",},
|
||||||
{"name":"s_node_3d_mesh_cylinder","order":1,"path":"sprites/s_node_3d_mesh_cylinder/s_node_3d_mesh_cylinder.yy",},
|
{"name":"s_node_3d_mesh_cylinder","order":1,"path":"sprites/s_node_3d_mesh_cylinder/s_node_3d_mesh_cylinder.yy",},
|
||||||
{"name":"s_node_3d_mesh_export","order":31,"path":"sprites/s_node_3d_mesh_export/s_node_3d_mesh_export.yy",},
|
{"name":"s_node_3d_mesh_export","order":31,"path":"sprites/s_node_3d_mesh_export/s_node_3d_mesh_export.yy",},
|
||||||
|
|
|
@ -346,6 +346,7 @@
|
||||||
{"$GMFolder":"","%Name":"rotator","folderPath":"folders/widgets/rotator.yy","name":"rotator","resourceType":"GMFolder","resourceVersion":"2.0",},
|
{"$GMFolder":"","%Name":"rotator","folderPath":"folders/widgets/rotator.yy","name":"rotator","resourceType":"GMFolder","resourceVersion":"2.0",},
|
||||||
{"$GMFolder":"","%Name":"sliders","folderPath":"folders/widgets/sliders.yy","name":"sliders","resourceType":"GMFolder","resourceVersion":"2.0",},
|
{"$GMFolder":"","%Name":"sliders","folderPath":"folders/widgets/sliders.yy","name":"sliders","resourceType":"GMFolder","resourceVersion":"2.0",},
|
||||||
{"$GMFolder":"","%Name":"text","folderPath":"folders/widgets/text.yy","name":"text","resourceType":"GMFolder","resourceVersion":"2.0",},
|
{"$GMFolder":"","%Name":"text","folderPath":"folders/widgets/text.yy","name":"text","resourceType":"GMFolder","resourceVersion":"2.0",},
|
||||||
|
{"$GMFolder":"","%Name":"blur zoom","folderPath":"folders/nodes/data/filter/blur/blur zoom.yy","name":"blur zoom","resourceType":"GMFolder","resourceVersion":"2.0",},
|
||||||
],
|
],
|
||||||
"IncludedFiles":[
|
"IncludedFiles":[
|
||||||
{"$GMIncludedFile":"","%Name":"Addons.zip","CopyToMask":-1,"filePath":"datafiles/data","name":"Addons.zip","resourceType":"GMIncludedFile","resourceVersion":"2.0",},
|
{"$GMIncludedFile":"","%Name":"Addons.zip","CopyToMask":-1,"filePath":"datafiles/data","name":"Addons.zip","resourceType":"GMIncludedFile","resourceVersion":"2.0",},
|
||||||
|
@ -3518,6 +3519,7 @@
|
||||||
{"id":{"name":"s_node_mk_saber","path":"sprites/s_node_mk_saber/s_node_mk_saber.yy",},},
|
{"id":{"name":"s_node_mk_saber","path":"sprites/s_node_mk_saber/s_node_mk_saber.yy",},},
|
||||||
{"id":{"name":"s_node_mk_sparkle","path":"sprites/s_node_mk_sparkle/s_node_mk_sparkle.yy",},},
|
{"id":{"name":"s_node_mk_sparkle","path":"sprites/s_node_mk_sparkle/s_node_mk_sparkle.yy",},},
|
||||||
{"id":{"name":"s_node_mk_subpixel","path":"sprites/s_node_mk_subpixel/s_node_mk_subpixel.yy",},},
|
{"id":{"name":"s_node_mk_subpixel","path":"sprites/s_node_mk_subpixel/s_node_mk_subpixel.yy",},},
|
||||||
|
{"id":{"name":"sh_blur_zoom_step","path":"shaders/sh_blur_zoom_step/sh_blur_zoom_step.yy",},},
|
||||||
{"id":{"name":"s_node_mk_tile","path":"sprites/s_node_mk_tile/s_node_mk_tile.yy",},},
|
{"id":{"name":"s_node_mk_tile","path":"sprites/s_node_mk_tile/s_node_mk_tile.yy",},},
|
||||||
{"id":{"name":"s_node_monitor_capture","path":"sprites/s_node_monitor_capture/s_node_monitor_capture.yy",},},
|
{"id":{"name":"s_node_monitor_capture","path":"sprites/s_node_monitor_capture/s_node_monitor_capture.yy",},},
|
||||||
{"id":{"name":"s_node_morph_surface","path":"sprites/s_node_morph_surface/s_node_morph_surface.yy",},},
|
{"id":{"name":"s_node_morph_surface","path":"sprites/s_node_morph_surface/s_node_morph_surface.yy",},},
|
||||||
|
|
Binary file not shown.
|
@ -12,7 +12,7 @@ function Node_Blur_Zoom(_x, _y, _group = noone) : Node_Processor(_x, _y, _group)
|
||||||
newInput(3, nodeValue_Enum_Scroll("Oversample mode", self, 0, [ "Empty", "Clamp", "Repeat" ]))
|
newInput(3, nodeValue_Enum_Scroll("Oversample mode", self, 0, [ "Empty", "Clamp", "Repeat" ]))
|
||||||
.setTooltip("How to deal with pixel outside the surface.\n - Empty: Use empty pixel\n - Clamp: Repeat edge pixel\n - Repeat: Repeat texture.");
|
.setTooltip("How to deal with pixel outside the surface.\n - Empty: Use empty pixel\n - Clamp: Repeat edge pixel\n - Repeat: Repeat texture.");
|
||||||
|
|
||||||
newInput(4, nodeValue_Enum_Scroll("Zoom mode", self, 1, [ "Start", "Middle", "End" ]));
|
newInput(4, nodeValue_Enum_Scroll("Zoom origin", self, 1, [ "Start", "Middle", "End" ]));
|
||||||
|
|
||||||
newInput(5, nodeValue_Surface("Blur mask", self));
|
newInput(5, nodeValue_Surface("Blur mask", self));
|
||||||
|
|
||||||
|
@ -38,11 +38,14 @@ function Node_Blur_Zoom(_x, _y, _group = noone) : Node_Processor(_x, _y, _group)
|
||||||
|
|
||||||
newInput(14, nodeValue_Int("Samples", self, 64));
|
newInput(14, nodeValue_Int("Samples", self, 64));
|
||||||
|
|
||||||
|
newInput(15, nodeValue_Enum_Button("Mode", self, 0, [ "Blur", "Step" ]));
|
||||||
|
|
||||||
newOutput(0, nodeValue_Output("Surface out", self, VALUE_TYPE.surface, noone));
|
newOutput(0, nodeValue_Output("Surface out", self, VALUE_TYPE.surface, noone));
|
||||||
|
|
||||||
input_display_list = [ 8, 9,
|
input_display_list = [ 8, 9,
|
||||||
["Surfaces", true], 0, 6, 7, 10, 11,
|
["Surfaces", true], 0, 6, 7, 10, 11, 5,
|
||||||
["Blur", false], 1, 12, 2, 4, 5, 13, 14,
|
["Blur", false], 15, 4, 1, 12, 2,
|
||||||
|
["Render", false], 14, 13,
|
||||||
];
|
];
|
||||||
|
|
||||||
attribute_surface_depth();
|
attribute_surface_depth();
|
||||||
|
@ -73,7 +76,7 @@ function Node_Blur_Zoom(_x, _y, _group = noone) : Node_Processor(_x, _y, _group)
|
||||||
_cen[0] /= surface_get_width_safe(_outSurf);
|
_cen[0] /= surface_get_width_safe(_outSurf);
|
||||||
_cen[1] /= surface_get_height_safe(_outSurf);
|
_cen[1] /= surface_get_height_safe(_outSurf);
|
||||||
|
|
||||||
surface_set_shader(_outSurf, sh_blur_zoom);
|
surface_set_shader(_outSurf, _data[15]? sh_blur_zoom_step : sh_blur_zoom);
|
||||||
shader_set_2("center", _cen);
|
shader_set_2("center", _cen);
|
||||||
shader_set_f_map("strength", _data[1], _data[12], inputs[1]);
|
shader_set_f_map("strength", _data[1], _data[12], inputs[1]);
|
||||||
shader_set_i("blurMode", _data[4]);
|
shader_set_i("blurMode", _data[4]);
|
||||||
|
|
|
@ -50,13 +50,13 @@ uniform sampler2D mask;
|
||||||
}
|
}
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
float sampleMask() { #region
|
float sampleMask() {
|
||||||
if(useMask == 0) return 1.;
|
if(useMask == 0) return 1.;
|
||||||
vec4 m = texture2D( mask, v_vTexcoord );
|
vec4 m = texture2D( mask, v_vTexcoord );
|
||||||
return (m.r + m.g + m.b) / 3. * m.a;
|
return (m.r + m.g + m.b) / 3. * m.a;
|
||||||
} #endregion
|
}
|
||||||
|
|
||||||
void main() { #region
|
void main() {
|
||||||
float str = strength.x;
|
float str = strength.x;
|
||||||
if(strengthUseSurf == 1) {
|
if(strengthUseSurf == 1) {
|
||||||
vec4 _vMap = texture2D( strengthSurf, v_vTexcoord );
|
vec4 _vMap = texture2D( strengthSurf, v_vTexcoord );
|
||||||
|
@ -88,4 +88,4 @@ void main() { #region
|
||||||
if(gamma == 1) color.rgb = pow(color.rgb, vec3(1. / 2.2));
|
if(gamma == 1) color.rgb = pow(color.rgb, vec3(1. / 2.2));
|
||||||
|
|
||||||
gl_FragColor = color;
|
gl_FragColor = color;
|
||||||
} #endregion
|
}
|
|
@ -3,8 +3,8 @@
|
||||||
"%Name":"sh_blur_zoom",
|
"%Name":"sh_blur_zoom",
|
||||||
"name":"sh_blur_zoom",
|
"name":"sh_blur_zoom",
|
||||||
"parent":{
|
"parent":{
|
||||||
"name":"blur",
|
"name":"blur zoom",
|
||||||
"path":"folders/nodes/data/filter/blur.yy",
|
"path":"folders/nodes/data/filter/blur/blur zoom.yy",
|
||||||
},
|
},
|
||||||
"resourceType":"GMShader",
|
"resourceType":"GMShader",
|
||||||
"resourceVersion":"2.0",
|
"resourceVersion":"2.0",
|
||||||
|
|
90
shaders/sh_blur_zoom_step/sh_blur_zoom_step.fsh
Normal file
90
shaders/sh_blur_zoom_step/sh_blur_zoom_step.fsh
Normal file
|
@ -0,0 +1,90 @@
|
||||||
|
#pragma use(sampler_simple)
|
||||||
|
|
||||||
|
#region -- sampler_simple -- [1729740692.1417658]
|
||||||
|
uniform int sampleMode;
|
||||||
|
|
||||||
|
vec4 sampleTexture( sampler2D texture, vec2 pos) {
|
||||||
|
if(pos.x >= 0. && pos.y >= 0. && pos.x <= 1. && pos.y <= 1.)
|
||||||
|
return texture2D(texture, pos);
|
||||||
|
|
||||||
|
if(sampleMode <= 1) return vec4(0.);
|
||||||
|
else if(sampleMode == 2) return texture2D(texture, clamp(pos, 0., 1.));
|
||||||
|
else if(sampleMode == 3) return texture2D(texture, fract(pos));
|
||||||
|
else if(sampleMode == 4) return vec4(vec3(0.), 1.);
|
||||||
|
|
||||||
|
return vec4(0.);
|
||||||
|
}
|
||||||
|
#endregion -- sampler_simple --
|
||||||
|
|
||||||
|
varying vec2 v_vTexcoord;
|
||||||
|
varying vec4 v_vColour;
|
||||||
|
uniform int samples;
|
||||||
|
|
||||||
|
uniform vec2 center;
|
||||||
|
uniform int blurMode;
|
||||||
|
uniform int gamma;
|
||||||
|
|
||||||
|
uniform vec2 strength;
|
||||||
|
uniform int strengthUseSurf;
|
||||||
|
uniform sampler2D strengthSurf;
|
||||||
|
|
||||||
|
uniform int useMask;
|
||||||
|
uniform sampler2D mask;
|
||||||
|
|
||||||
|
#region ==== PARAM DRIVER ====
|
||||||
|
#define PARAM_COUNT 1
|
||||||
|
uniform int parameter_active[PARAM_COUNT];
|
||||||
|
uniform sampler2D parameters;
|
||||||
|
|
||||||
|
float sampleParameter(in int index, in float def) {
|
||||||
|
if(parameter_active[index] == 0) return def;
|
||||||
|
float row = floor(float(index) / 4.);
|
||||||
|
vec2 coord = (v_vTexcoord + vec2(float(index) - row * 4., row)) * 0.25;
|
||||||
|
vec4 col = texture2D( parameters, coord );
|
||||||
|
|
||||||
|
float _val = col.r;
|
||||||
|
float _min = col.g * 256. - 128.;
|
||||||
|
float _max = col.b * 256. - 128.;
|
||||||
|
|
||||||
|
return mix(_min, _max, _val);
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
float sampleMask() {
|
||||||
|
if(useMask == 0) return 1.;
|
||||||
|
vec4 m = texture2D( mask, v_vTexcoord );
|
||||||
|
return (m.r + m.g + m.b) / 3. * m.a;
|
||||||
|
}
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
float str = strength.x;
|
||||||
|
if(strengthUseSurf == 1) {
|
||||||
|
vec4 _vMap = texture2D( strengthSurf, v_vTexcoord );
|
||||||
|
str = mix(strength.x, strength.y, (_vMap.r + _vMap.g + _vMap.b) / 3.);
|
||||||
|
}
|
||||||
|
|
||||||
|
vec2 uv = v_vTexcoord - center;
|
||||||
|
|
||||||
|
float _str = sampleParameter(0, str) * sampleMask();
|
||||||
|
float nsamples = float(samples);
|
||||||
|
float scale_factor = _str * (1. / (nsamples * 2. - 1.));
|
||||||
|
float blrStart = 0.;
|
||||||
|
|
||||||
|
if(blurMode == 0) blrStart = 0.;
|
||||||
|
else if(blurMode == 1) blrStart = -nsamples;
|
||||||
|
else if(blurMode == 2) blrStart = -nsamples * 2. - 1.;
|
||||||
|
|
||||||
|
vec4 color = vec4(0.0);
|
||||||
|
for(float i = 0.; i < nsamples * 2. + 1.; i++) {
|
||||||
|
float scale = 1.0 + ((blrStart + i) * scale_factor);
|
||||||
|
vec2 pos = uv * scale + center;
|
||||||
|
|
||||||
|
vec4 col = sampleTexture( gm_BaseTexture, pos );
|
||||||
|
if(col.a > 0.) {
|
||||||
|
color = col;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
gl_FragColor = color;
|
||||||
|
}
|
14
shaders/sh_blur_zoom_step/sh_blur_zoom_step.vsh
Normal file
14
shaders/sh_blur_zoom_step/sh_blur_zoom_step.vsh
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
attribute vec3 in_Position; // (x, y, z)
|
||||||
|
attribute vec4 in_Colour; // (r, g, b, a)
|
||||||
|
attribute vec2 in_TextureCoord; // (u, v)
|
||||||
|
|
||||||
|
varying vec2 v_vTexcoord;
|
||||||
|
varying vec4 v_vColour;
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
vec4 object_space_pos = vec4(in_Position.x, in_Position.y, in_Position.z, 1.0);
|
||||||
|
gl_Position = gm_Matrices[MATRIX_WORLD_VIEW_PROJECTION] * object_space_pos;
|
||||||
|
|
||||||
|
v_vColour = in_Colour;
|
||||||
|
v_vTexcoord = in_TextureCoord;
|
||||||
|
}
|
13
shaders/sh_blur_zoom_step/sh_blur_zoom_step.yy
Normal file
13
shaders/sh_blur_zoom_step/sh_blur_zoom_step.yy
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
{
|
||||||
|
"$GMShader":"",
|
||||||
|
"%Name":"sh_blur_zoom_step",
|
||||||
|
"name":"sh_blur_zoom_step",
|
||||||
|
"parent":{
|
||||||
|
"name":"blur zoom",
|
||||||
|
"path":"folders/nodes/data/filter/blur/blur zoom.yy",
|
||||||
|
},
|
||||||
|
"resourceType":"GMShader",
|
||||||
|
"resourceVersion":"2.0",
|
||||||
|
"tags":[],
|
||||||
|
"type":1,
|
||||||
|
}
|
Loading…
Reference in a new issue