mirror of
https://github.com/melonDS-emu/melonDS.git
synced 2025-06-28 09:59:41 -06:00
try to fix fog consecutively to the Intel fix. still not perfect for whatever reason
also clean up more code
This commit is contained in:
@ -188,11 +188,6 @@ bool Init()
|
|||||||
{
|
{
|
||||||
GLint uni_id;
|
GLint uni_id;
|
||||||
|
|
||||||
const GLubyte* renderer = glGetString(GL_RENDERER); // get renderer string
|
|
||||||
const GLubyte* version = glGetString(GL_VERSION); // version as a string
|
|
||||||
printf("OpenGL: renderer: %s\n", renderer);
|
|
||||||
printf("OpenGL: version: %s\n", version);
|
|
||||||
|
|
||||||
glEnable(GL_DEPTH_TEST);
|
glEnable(GL_DEPTH_TEST);
|
||||||
glEnable(GL_STENCIL_TEST);
|
glEnable(GL_STENCIL_TEST);
|
||||||
|
|
||||||
|
@ -42,14 +42,14 @@ uniform uint uOpaquePolyID;
|
|||||||
uniform uint uFogFlag;
|
uniform uint uFogFlag;
|
||||||
|
|
||||||
out vec4 oColor;
|
out vec4 oColor;
|
||||||
out uvec3 oAttr;
|
out vec3 oAttr;
|
||||||
|
|
||||||
void main()
|
void main()
|
||||||
{
|
{
|
||||||
oColor = vec4(uColor).bgra / 31.0;
|
oColor = vec4(uColor).bgra / 31.0;
|
||||||
oAttr.r = uOpaquePolyID;
|
oAttr.r = float(uOpaquePolyID) / 63.0;
|
||||||
oAttr.g = uint(0);
|
oAttr.g = 0;
|
||||||
oAttr.b = uFogFlag;
|
oAttr.b = float(uFogFlag);
|
||||||
}
|
}
|
||||||
)";
|
)";
|
||||||
|
|
||||||
@ -69,7 +69,7 @@ void main()
|
|||||||
const char* kFinalPassFS = kShaderHeader R"(
|
const char* kFinalPassFS = kShaderHeader R"(
|
||||||
|
|
||||||
uniform sampler2D DepthBuffer;
|
uniform sampler2D DepthBuffer;
|
||||||
uniform usampler2D AttrBuffer;
|
uniform sampler2D AttrBuffer;
|
||||||
|
|
||||||
layout(std140) uniform uConfig
|
layout(std140) uniform uConfig
|
||||||
{
|
{
|
||||||
@ -122,7 +122,7 @@ void main()
|
|||||||
|
|
||||||
vec4 ret = vec4(0,0,0,0);
|
vec4 ret = vec4(0,0,0,0);
|
||||||
vec4 depth = texelFetch(DepthBuffer, coord, 0);
|
vec4 depth = texelFetch(DepthBuffer, coord, 0);
|
||||||
ivec4 attr = ivec4(texelFetch(AttrBuffer, coord, 0));
|
vec4 attr = texelFetch(AttrBuffer, coord, 0);
|
||||||
|
|
||||||
if (attr.b != 0) ret = CalculateFog(depth.r);
|
if (attr.b != 0) ret = CalculateFog(depth.r);
|
||||||
|
|
||||||
@ -178,7 +178,7 @@ smooth in vec2 fTexcoord;
|
|||||||
flat in ivec3 fPolygonAttr;
|
flat in ivec3 fPolygonAttr;
|
||||||
|
|
||||||
out vec4 oColor;
|
out vec4 oColor;
|
||||||
out uvec3 oAttr;
|
out vec3 oAttr;
|
||||||
|
|
||||||
int TexcoordWrap(int c, int maxc, int mode)
|
int TexcoordWrap(int c, int maxc, int mode)
|
||||||
{
|
{
|
||||||
@ -618,8 +618,8 @@ void main()
|
|||||||
if (col.a < 30.5/31) discard;
|
if (col.a < 30.5/31) discard;
|
||||||
|
|
||||||
oColor = col;
|
oColor = col;
|
||||||
oAttr.r = uint((fPolygonAttr.x >> 24) & 0x3F);
|
oAttr.r = float((fPolygonAttr.x >> 24) & 0x3F) / 63.0;
|
||||||
oAttr.b = uint((fPolygonAttr.x >> 15) & 0x1);
|
oAttr.b = float((fPolygonAttr.x >> 15) & 0x1);
|
||||||
}
|
}
|
||||||
)";
|
)";
|
||||||
|
|
||||||
@ -633,8 +633,8 @@ void main()
|
|||||||
if (col.a < 30.5/31) discard;
|
if (col.a < 30.5/31) discard;
|
||||||
|
|
||||||
oColor = col;
|
oColor = col;
|
||||||
oAttr.r = uint((fPolygonAttr.x >> 24) & 0x3F);
|
oAttr.r = float((fPolygonAttr.x >> 24) & 0x3F) / 63.0;
|
||||||
oAttr.b = uint((fPolygonAttr.x >> 15) & 0x1);
|
oAttr.b = float((fPolygonAttr.x >> 15) & 0x1);
|
||||||
gl_FragDepth = fZ;
|
gl_FragDepth = fZ;
|
||||||
}
|
}
|
||||||
)";
|
)";
|
||||||
@ -648,7 +648,7 @@ void main()
|
|||||||
if (col.a >= 30.5/31) discard;
|
if (col.a >= 30.5/31) discard;
|
||||||
|
|
||||||
oColor = col;
|
oColor = col;
|
||||||
oAttr.b = uint(0);
|
oAttr.b = 0;
|
||||||
}
|
}
|
||||||
)";
|
)";
|
||||||
|
|
||||||
@ -663,7 +663,7 @@ void main()
|
|||||||
if (col.a >= 30.5/31) discard;
|
if (col.a >= 30.5/31) discard;
|
||||||
|
|
||||||
oColor = col;
|
oColor = col;
|
||||||
oAttr.b = uint(0);
|
oAttr.b = 0;
|
||||||
gl_FragDepth = fZ;
|
gl_FragDepth = fZ;
|
||||||
}
|
}
|
||||||
)";
|
)";
|
||||||
|
@ -115,67 +115,46 @@ void freeGLContext(uiGLContext* glctx)
|
|||||||
|
|
||||||
static void areaAllocRenderbuffer(uiGLContext* glctx)
|
static void areaAllocRenderbuffer(uiGLContext* glctx)
|
||||||
{
|
{
|
||||||
_glGenRenderbuffers(4, &glctx->renderbuffer[0][0]);printf("ylarg0 %04X, %d %d\n", glGetError(), glctx->width, glctx->height);
|
// TODO: create textures as a fallback if GL_RGB renderbuffer isn't supported?
|
||||||
//glGenTextures(2, &glctx->renderbuffer[0]);
|
// they say GL implementations aren't required to support a GL_RGB renderbuffer
|
||||||
_glGenFramebuffers(2, &glctx->framebuffer[0]);printf("ylarg1 %04X\n", glGetError());
|
// however, a GL_RGBA one would cause gdk_cairo_draw_from_gl() to fall back to glReadPixels()
|
||||||
printf("FB %08X created under ctx %p (%p %p)\n", glctx?glctx->framebuffer[0]:0, gdk_gl_context_get_current(), glctx?glctx->gctx:NULL, glctx);
|
|
||||||
/*glBindTexture(GL_TEXTURE_2D, glctx->renderbuffer[0]);
|
|
||||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
|
||||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
|
||||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
|
||||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
|
||||||
|
|
||||||
glBindTexture(GL_TEXTURE_2D, glctx->renderbuffer[1]);
|
_glGenRenderbuffers(4, &glctx->renderbuffer[0][0]);
|
||||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
_glGenFramebuffers(2, &glctx->framebuffer[0]);
|
||||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
|
||||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
|
||||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);*/
|
|
||||||
|
|
||||||
_glBindRenderbuffer(GL_RENDERBUFFER, glctx->renderbuffer[0][0]);printf("ylarg1 %04X\n", glGetError());
|
|
||||||
_glRenderbufferStorage(GL_RENDERBUFFER, GL_RGB, glctx->width*glctx->scale, glctx->height*glctx->scale);printf("ylarg1 %04X\n", glGetError());
|
|
||||||
_glBindRenderbuffer(GL_RENDERBUFFER, glctx->renderbuffer[0][1]);printf("ylarg1 %04X\n", glGetError());
|
|
||||||
_glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_STENCIL, glctx->width*glctx->scale, glctx->height*glctx->scale);printf("ylarg1 %04X\n", glGetError());
|
|
||||||
|
|
||||||
_glBindFramebuffer(GL_FRAMEBUFFER, glctx->framebuffer[0]);printf("ylarg2 %04X\n", glGetError());
|
|
||||||
/*_glFramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, glctx->renderbuffer[0], 0);
|
|
||||||
_glFramebufferTexture(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, glctx->renderbuffer[1], 0);*/
|
|
||||||
_glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, glctx->renderbuffer[0][0]);printf("ylarg3 %04X\n", glGetError());
|
|
||||||
_glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER, glctx->renderbuffer[0][1]);printf("ylarg4 %04X\n", glGetError());
|
|
||||||
//printf("ylarg: %08X, %04X, %08X %08X\n", glctx->framebuffer, glGetError(), glctx->renderbuffer[0], glctx->renderbuffer[1]);
|
|
||||||
|
|
||||||
|
|
||||||
_glBindRenderbuffer(GL_RENDERBUFFER, glctx->renderbuffer[1][0]);printf("ylarg1 %04X\n", glGetError());
|
|
||||||
_glRenderbufferStorage(GL_RENDERBUFFER, GL_RGB, glctx->width*glctx->scale, glctx->height*glctx->scale);printf("ylarg1 %04X\n", glGetError());
|
|
||||||
_glBindRenderbuffer(GL_RENDERBUFFER, glctx->renderbuffer[1][1]);printf("ylarg1 %04X\n", glGetError());
|
|
||||||
_glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_STENCIL, glctx->width*glctx->scale, glctx->height*glctx->scale);printf("ylarg1 %04X\n", glGetError());
|
|
||||||
|
|
||||||
_glBindFramebuffer(GL_FRAMEBUFFER, glctx->framebuffer[1]);printf("ylarg2 %04X\n", glGetError());
|
|
||||||
/*_glFramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, glctx->renderbuffer[0], 0);
|
|
||||||
_glFramebufferTexture(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, glctx->renderbuffer[1], 0);*/
|
|
||||||
_glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, glctx->renderbuffer[1][0]);printf("ylarg3 %04X\n", glGetError());
|
|
||||||
_glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER, glctx->renderbuffer[1][1]);printf("ylarg4 %04X\n", glGetError());
|
|
||||||
//printf("ylarg: %08X, %04X, %08X %08X\n", glctx->framebuffer, glGetError(), glctx->renderbuffer[0], glctx->renderbuffer[1]);
|
|
||||||
|
|
||||||
if(_glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
|
|
||||||
printf("FRAMEBUFFER IS BAD!! %04X\n", _glCheckFramebufferStatus(GL_FRAMEBUFFER));
|
|
||||||
|
|
||||||
int alpha_size;
|
|
||||||
_glBindRenderbuffer(GL_RENDERBUFFER, glctx->renderbuffer[0][0]);
|
_glBindRenderbuffer(GL_RENDERBUFFER, glctx->renderbuffer[0][0]);
|
||||||
_glGetRenderbufferParameteriv (GL_RENDERBUFFER, GL_RENDERBUFFER_ALPHA_SIZE, &alpha_size);
|
_glRenderbufferStorage(GL_RENDERBUFFER, GL_RGB, glctx->width*glctx->scale, glctx->height*glctx->scale);
|
||||||
printf("FRAMEBUFFER GOOD. ALPHA SIZE IS %d\n", alpha_size);
|
//_glBindRenderbuffer(GL_RENDERBUFFER, glctx->renderbuffer[0][1]);
|
||||||
|
//_glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_STENCIL, glctx->width*glctx->scale, glctx->height*glctx->scale);
|
||||||
|
|
||||||
|
_glBindFramebuffer(GL_FRAMEBUFFER, glctx->framebuffer[0]);
|
||||||
|
_glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, glctx->renderbuffer[0][0]);
|
||||||
|
_glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER, glctx->renderbuffer[0][1]);
|
||||||
|
|
||||||
|
_glBindRenderbuffer(GL_RENDERBUFFER, glctx->renderbuffer[1][0]);
|
||||||
|
_glRenderbufferStorage(GL_RENDERBUFFER, GL_RGB, glctx->width*glctx->scale, glctx->height*glctx->scale);
|
||||||
|
//_glBindRenderbuffer(GL_RENDERBUFFER, glctx->renderbuffer[1][1]);
|
||||||
|
//_glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_STENCIL, glctx->width*glctx->scale, glctx->height*glctx->scale);
|
||||||
|
|
||||||
|
_glBindFramebuffer(GL_FRAMEBUFFER, glctx->framebuffer[1]);
|
||||||
|
_glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, glctx->renderbuffer[1][0]);
|
||||||
|
_glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER, glctx->renderbuffer[1][1]);
|
||||||
|
|
||||||
|
//if (_glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
|
||||||
|
// printf("FRAMEBUFFER IS BAD!! %04X\n", _glCheckFramebufferStatus(GL_FRAMEBUFFER));
|
||||||
}
|
}
|
||||||
|
|
||||||
static void areaRellocRenderbuffer(uiGLContext* glctx)
|
static void areaRellocRenderbuffer(uiGLContext* glctx)
|
||||||
{
|
{
|
||||||
_glBindRenderbuffer(GL_RENDERBUFFER, glctx->renderbuffer[0][0]);
|
_glBindRenderbuffer(GL_RENDERBUFFER, glctx->renderbuffer[0][0]);
|
||||||
_glRenderbufferStorage(GL_RENDERBUFFER, GL_RGB, glctx->width*glctx->scale, glctx->height*glctx->scale);
|
_glRenderbufferStorage(GL_RENDERBUFFER, GL_RGB, glctx->width*glctx->scale, glctx->height*glctx->scale);
|
||||||
_glBindRenderbuffer(GL_RENDERBUFFER, glctx->renderbuffer[0][1]);
|
//_glBindRenderbuffer(GL_RENDERBUFFER, glctx->renderbuffer[0][1]);
|
||||||
_glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_STENCIL, glctx->width*glctx->scale, glctx->height*glctx->scale);
|
//_glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_STENCIL, glctx->width*glctx->scale, glctx->height*glctx->scale);
|
||||||
|
|
||||||
_glBindRenderbuffer(GL_RENDERBUFFER, glctx->renderbuffer[1][0]);
|
_glBindRenderbuffer(GL_RENDERBUFFER, glctx->renderbuffer[1][0]);
|
||||||
_glRenderbufferStorage(GL_RENDERBUFFER, GL_RGB, glctx->width*glctx->scale, glctx->height*glctx->scale);
|
_glRenderbufferStorage(GL_RENDERBUFFER, GL_RGB, glctx->width*glctx->scale, glctx->height*glctx->scale);
|
||||||
_glBindRenderbuffer(GL_RENDERBUFFER, glctx->renderbuffer[1][1]);
|
//_glBindRenderbuffer(GL_RENDERBUFFER, glctx->renderbuffer[1][1]);
|
||||||
_glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_STENCIL, glctx->width*glctx->scale, glctx->height*glctx->scale);
|
//_glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_STENCIL, glctx->width*glctx->scale, glctx->height*glctx->scale);
|
||||||
}
|
}
|
||||||
|
|
||||||
void areaPreRedrawGL(uiGLContext* glctx)
|
void areaPreRedrawGL(uiGLContext* glctx)
|
||||||
|
@ -194,12 +194,11 @@ bool GLScreen_InitShader(GLuint* shader, const char* fs)
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool GLScreen_Init()
|
bool GLScreen_Init()
|
||||||
{printf("BEGINNING GL SHITO\n");
|
{
|
||||||
|
// TODO: consider using epoxy?
|
||||||
if (!OpenGL_Init())
|
if (!OpenGL_Init())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
printf("GL INIT: %p, %p\n", glGenFramebuffers, glCreateShader);
|
|
||||||
|
|
||||||
const GLubyte* renderer = glGetString(GL_RENDERER); // get renderer string
|
const GLubyte* renderer = glGetString(GL_RENDERER); // get renderer string
|
||||||
const GLubyte* version = glGetString(GL_VERSION); // version as a string
|
const GLubyte* version = glGetString(GL_VERSION); // version as a string
|
||||||
printf("OpenGL: renderer: %s\n", renderer);
|
printf("OpenGL: renderer: %s\n", renderer);
|
||||||
@ -211,7 +210,7 @@ bool GLScreen_Init()
|
|||||||
return false;
|
return false;
|
||||||
|
|
||||||
memset(&GL_ShaderConfig, 0, sizeof(GL_ShaderConfig));
|
memset(&GL_ShaderConfig, 0, sizeof(GL_ShaderConfig));
|
||||||
printf("morp0\n");
|
|
||||||
glGenBuffers(1, &GL_ShaderConfigUBO);
|
glGenBuffers(1, &GL_ShaderConfigUBO);
|
||||||
glBindBuffer(GL_UNIFORM_BUFFER, GL_ShaderConfigUBO);
|
glBindBuffer(GL_UNIFORM_BUFFER, GL_ShaderConfigUBO);
|
||||||
glBufferData(GL_UNIFORM_BUFFER, sizeof(GL_ShaderConfig), &GL_ShaderConfig, GL_STATIC_DRAW);
|
glBufferData(GL_UNIFORM_BUFFER, sizeof(GL_ShaderConfig), &GL_ShaderConfig, GL_STATIC_DRAW);
|
||||||
@ -220,14 +219,14 @@ printf("morp0\n");
|
|||||||
glGenBuffers(1, &GL_ScreenVertexBufferID);
|
glGenBuffers(1, &GL_ScreenVertexBufferID);
|
||||||
glBindBuffer(GL_ARRAY_BUFFER, GL_ScreenVertexBufferID);
|
glBindBuffer(GL_ARRAY_BUFFER, GL_ScreenVertexBufferID);
|
||||||
glBufferData(GL_ARRAY_BUFFER, sizeof(GL_ScreenVertices), NULL, GL_STATIC_DRAW);
|
glBufferData(GL_ARRAY_BUFFER, sizeof(GL_ScreenVertices), NULL, GL_STATIC_DRAW);
|
||||||
printf("morp1\n");
|
|
||||||
glGenVertexArrays(1, &GL_ScreenVertexArrayID);
|
glGenVertexArrays(1, &GL_ScreenVertexArrayID);
|
||||||
glBindVertexArray(GL_ScreenVertexArrayID);
|
glBindVertexArray(GL_ScreenVertexArrayID);
|
||||||
glEnableVertexAttribArray(0); // position
|
glEnableVertexAttribArray(0); // position
|
||||||
glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 4*4, (void*)(0));
|
glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 4*4, (void*)(0));
|
||||||
glEnableVertexAttribArray(1); // texcoord
|
glEnableVertexAttribArray(1); // texcoord
|
||||||
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 4*4, (void*)(2*4));
|
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 4*4, (void*)(2*4));
|
||||||
printf("morp2\n");
|
|
||||||
glGenTextures(1, &GL_ScreenTexture);
|
glGenTextures(1, &GL_ScreenTexture);
|
||||||
glActiveTexture(GL_TEXTURE0);
|
glActiveTexture(GL_TEXTURE0);
|
||||||
glBindTexture(GL_TEXTURE_2D, GL_ScreenTexture);
|
glBindTexture(GL_TEXTURE_2D, GL_ScreenTexture);
|
||||||
@ -238,7 +237,7 @@ printf("morp2\n");
|
|||||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8UI, 256*3 + 1, 192*2, 0, GL_RGBA_INTEGER, GL_UNSIGNED_BYTE, NULL);
|
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8UI, 256*3 + 1, 192*2, 0, GL_RGBA_INTEGER, GL_UNSIGNED_BYTE, NULL);
|
||||||
|
|
||||||
GL_ScreenSizeDirty = true;
|
GL_ScreenSizeDirty = true;
|
||||||
printf("morp3\n");
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -394,7 +393,7 @@ void GLScreen_DrawScreen()
|
|||||||
|
|
||||||
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, uiGLGetFramebuffer(GLContext));
|
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, uiGLGetFramebuffer(GLContext));
|
||||||
|
|
||||||
glClearColor(0, 0, 1, 1);
|
glClearColor(0, 0, 0, 1);
|
||||||
glClear(GL_COLOR_BUFFER_BIT);
|
glClear(GL_COLOR_BUFFER_BIT);
|
||||||
|
|
||||||
int frontbuf = GPU::FrontBuffer;
|
int frontbuf = GPU::FrontBuffer;
|
||||||
|
Reference in New Issue
Block a user