mirror of
https://github.com/minetest/irrlicht.git
synced 2024-11-18 05:33:52 +01:00
OpenGL3: Sort out texture color format support
This commit is contained in:
parent
49b6ccde72
commit
1387370260
@ -2111,226 +2111,17 @@ COpenGL3DriverBase::~COpenGL3DriverBase()
|
||||
bool COpenGL3DriverBase::getColorFormatParameters(ECOLOR_FORMAT format, GLint& internalFormat, GLenum& pixelFormat,
|
||||
GLenum& pixelType, void(**converter)(const void*, s32, void*)) const
|
||||
{
|
||||
bool supported = false;
|
||||
pixelFormat = GL_RGBA;
|
||||
pixelType = GL_UNSIGNED_BYTE;
|
||||
*converter = 0;
|
||||
|
||||
switch (format)
|
||||
{
|
||||
case ECF_A1R5G5B5:
|
||||
supported = true;
|
||||
pixelFormat = GL_RGBA;
|
||||
pixelType = GL_UNSIGNED_SHORT_5_5_5_1;
|
||||
*converter = CColorConverter::convert_A1R5G5B5toR5G5B5A1;
|
||||
break;
|
||||
case ECF_R5G6B5:
|
||||
supported = true;
|
||||
pixelFormat = GL_RGB;
|
||||
pixelType = GL_UNSIGNED_SHORT_5_6_5;
|
||||
break;
|
||||
case ECF_R8G8B8:
|
||||
supported = true;
|
||||
pixelFormat = GL_RGB;
|
||||
pixelType = GL_UNSIGNED_BYTE;
|
||||
break;
|
||||
case ECF_A8R8G8B8:
|
||||
supported = true;
|
||||
if (queryGLESFeature(COGLESCoreExtensionHandler::IRR_GL_IMG_texture_format_BGRA8888) ||
|
||||
queryGLESFeature(COGLESCoreExtensionHandler::IRR_GL_EXT_texture_format_BGRA8888) ||
|
||||
queryGLESFeature(COGLESCoreExtensionHandler::IRR_GL_APPLE_texture_format_BGRA8888))
|
||||
{
|
||||
pixelFormat = GL_BGRA;
|
||||
}
|
||||
else
|
||||
{
|
||||
pixelFormat = GL_RGBA;
|
||||
*converter = CColorConverter::convert_A8R8G8B8toA8B8G8R8;
|
||||
}
|
||||
pixelType = GL_UNSIGNED_BYTE;
|
||||
break;
|
||||
#ifdef GL_EXT_texture_compression_s3tc
|
||||
case ECF_DXT1:
|
||||
supported = true;
|
||||
pixelFormat = GL_RGBA;
|
||||
pixelType = GL_COMPRESSED_RGBA_S3TC_DXT1_EXT;
|
||||
break;
|
||||
case ECF_DXT2:
|
||||
case ECF_DXT3:
|
||||
supported = true;
|
||||
pixelFormat = GL_RGBA;
|
||||
pixelType = GL_COMPRESSED_RGBA_S3TC_DXT3_EXT;
|
||||
break;
|
||||
case ECF_DXT4:
|
||||
case ECF_DXT5:
|
||||
supported = true;
|
||||
pixelFormat = GL_RGBA;
|
||||
pixelType = GL_COMPRESSED_RGBA_S3TC_DXT5_EXT;
|
||||
break;
|
||||
#endif
|
||||
#ifdef GL_OES_compressed_ETC1_RGB8_texture
|
||||
case ECF_ETC1:
|
||||
supported = true;
|
||||
pixelFormat = GL_RGB;
|
||||
pixelType = GL_ETC1_RGB8_OES;
|
||||
break;
|
||||
#endif
|
||||
#ifdef GL_ES_VERSION_3_0 // TO-DO - fix when extension name will be available
|
||||
case ECF_ETC2_RGB:
|
||||
supported = true;
|
||||
pixelFormat = GL_RGB;
|
||||
pixelType = GL_COMPRESSED_RGB8_ETC2;
|
||||
break;
|
||||
#endif
|
||||
#ifdef GL_ES_VERSION_3_0 // TO-DO - fix when extension name will be available
|
||||
case ECF_ETC2_ARGB:
|
||||
supported = true;
|
||||
pixelFormat = GL_RGBA;
|
||||
pixelType = GL_COMPRESSED_RGBA8_ETC2_EAC;
|
||||
break;
|
||||
#endif
|
||||
case ECF_D16:
|
||||
supported = true;
|
||||
pixelFormat = GL_DEPTH_COMPONENT;
|
||||
pixelType = GL_UNSIGNED_SHORT;
|
||||
break;
|
||||
case ECF_D32:
|
||||
#if defined(GL_OES_depth32)
|
||||
if (queryGLESFeature(COGLESCoreExtensionHandler::IRR_GL_OES_depth32))
|
||||
{
|
||||
supported = true;
|
||||
pixelFormat = GL_DEPTH_COMPONENT;
|
||||
pixelType = GL_UNSIGNED_INT;
|
||||
}
|
||||
#endif
|
||||
break;
|
||||
case ECF_D24S8:
|
||||
#ifdef GL_OES_packed_depth_stencil
|
||||
if (queryGLESFeature(COGLESCoreExtensionHandler::IRR_GL_OES_packed_depth_stencil))
|
||||
{
|
||||
supported = true;
|
||||
pixelFormat = GL_DEPTH_STENCIL_OES;
|
||||
pixelType = GL_UNSIGNED_INT_24_8_OES;
|
||||
}
|
||||
#endif
|
||||
break;
|
||||
case ECF_R8:
|
||||
#if defined(GL_EXT_texture_rg)
|
||||
if (queryGLESFeature(COGLESCoreExtensionHandler::IRR_GL_EXT_texture_rg))
|
||||
{
|
||||
supported = true;
|
||||
pixelFormat = GL_RED_EXT;
|
||||
pixelType = GL_UNSIGNED_BYTE;
|
||||
}
|
||||
#endif
|
||||
break;
|
||||
case ECF_R8G8:
|
||||
#if defined(GL_EXT_texture_rg)
|
||||
if (queryGLESFeature(COGLESCoreExtensionHandler::IRR_GL_EXT_texture_rg))
|
||||
{
|
||||
supported = true;
|
||||
pixelFormat = GL_RG_EXT;
|
||||
pixelType = GL_UNSIGNED_BYTE;
|
||||
}
|
||||
#endif
|
||||
break;
|
||||
case ECF_R16:
|
||||
break;
|
||||
case ECF_R16G16:
|
||||
break;
|
||||
case ECF_R16F:
|
||||
#if defined(GL_OES_texture_half_float) && defined(GL_EXT_texture_rg)
|
||||
if (queryGLESFeature(COGLESCoreExtensionHandler::IRR_GL_EXT_texture_rg)
|
||||
&& queryGLESFeature(COGLESCoreExtensionHandler::IRR_GL_OES_texture_half_float)
|
||||
)
|
||||
{
|
||||
supported = true;
|
||||
pixelFormat = GL_RED_EXT;
|
||||
pixelType = GL_HALF_FLOAT_OES ;
|
||||
}
|
||||
#endif
|
||||
break;
|
||||
case ECF_G16R16F:
|
||||
#if defined(GL_OES_texture_half_float) && defined(GL_EXT_texture_rg)
|
||||
if (queryGLESFeature(COGLESCoreExtensionHandler::IRR_GL_EXT_texture_rg)
|
||||
&& queryGLESFeature(COGLESCoreExtensionHandler::IRR_GL_OES_texture_half_float)
|
||||
)
|
||||
{
|
||||
supported = true;
|
||||
pixelFormat = GL_RG_EXT;
|
||||
pixelType = GL_HALF_FLOAT_OES ;
|
||||
}
|
||||
#endif
|
||||
break;
|
||||
case ECF_A16B16G16R16F:
|
||||
#if defined(GL_OES_texture_half_float)
|
||||
if (queryGLESFeature(COGLESCoreExtensionHandler::IRR_GL_OES_texture_half_float))
|
||||
{
|
||||
supported = true;
|
||||
pixelFormat = GL_RGBA;
|
||||
pixelType = GL_HALF_FLOAT_OES ;
|
||||
}
|
||||
#endif
|
||||
break;
|
||||
case ECF_R32F:
|
||||
#if defined(GL_OES_texture_float) && defined(GL_EXT_texture_rg)
|
||||
if (queryGLESFeature(COGLESCoreExtensionHandler::IRR_GL_EXT_texture_rg)
|
||||
&& queryGLESFeature(COGLESCoreExtensionHandler::IRR_GL_OES_texture_float)
|
||||
)
|
||||
{
|
||||
supported = true;
|
||||
pixelFormat = GL_RED_EXT;
|
||||
pixelType = GL_FLOAT;
|
||||
}
|
||||
#endif
|
||||
break;
|
||||
case ECF_G32R32F:
|
||||
#if defined(GL_OES_texture_float) && defined(GL_EXT_texture_rg)
|
||||
if (queryGLESFeature(COGLESCoreExtensionHandler::IRR_GL_EXT_texture_rg)
|
||||
&& queryGLESFeature(COGLESCoreExtensionHandler::IRR_GL_OES_texture_float)
|
||||
)
|
||||
{
|
||||
supported = true;
|
||||
pixelFormat = GL_RG_EXT;
|
||||
pixelType = GL_FLOAT;
|
||||
}
|
||||
#endif
|
||||
break;
|
||||
case ECF_A32B32G32R32F:
|
||||
#if defined(GL_OES_texture_float)
|
||||
if (queryGLESFeature(COGLESCoreExtensionHandler::IRR_GL_OES_texture_half_float))
|
||||
{
|
||||
supported = true;
|
||||
pixelFormat = GL_RGBA;
|
||||
pixelType = GL_FLOAT ;
|
||||
}
|
||||
#endif
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
// ES 2.0 says internalFormat must match pixelFormat (chapter 3.7.1 in Spec).
|
||||
// Doesn't mention if "match" means "equal" or some other way of matching, but
|
||||
// some bug on Emscripten and browsing discussions by others lead me to believe
|
||||
// it means they have to be equal. Note that this was different in OpenGL.
|
||||
internalFormat = pixelFormat;
|
||||
|
||||
#ifdef _IRR_IOS_PLATFORM_
|
||||
if (internalFormat == GL_BGRA)
|
||||
internalFormat = GL_RGBA;
|
||||
#endif
|
||||
|
||||
return supported;
|
||||
auto &info = TextureFormats[format];
|
||||
internalFormat = info.InternalFormat;
|
||||
pixelFormat = info.PixelFormat;
|
||||
pixelType = info.PixelType;
|
||||
*converter = info.Converter;
|
||||
return info.InternalFormat != 0;
|
||||
}
|
||||
|
||||
bool COpenGL3DriverBase::queryTextureFormat(ECOLOR_FORMAT format) const
|
||||
{
|
||||
GLint dummyInternalFormat;
|
||||
GLenum dummyPixelFormat;
|
||||
GLenum dummyPixelType;
|
||||
void (*dummyConverter)(const void*, s32, void*);
|
||||
return getColorFormatParameters(format, dummyInternalFormat, dummyPixelFormat, dummyPixelType, &dummyConverter);
|
||||
return TextureFormats[format].InternalFormat != 0;
|
||||
}
|
||||
|
||||
bool COpenGL3DriverBase::needsTransparentRenderPass(const irr::video::SMaterial& material) const
|
||||
|
@ -365,6 +365,15 @@ namespace video
|
||||
|
||||
core::matrix4 TextureFlipMatrix;
|
||||
|
||||
using FColorConverter = void(*)(const void *source, s32 count, void *dest);
|
||||
struct STextureFormatInfo {
|
||||
GLenum InternalFormat;
|
||||
GLenum PixelFormat;
|
||||
GLenum PixelType;
|
||||
FColorConverter Converter;
|
||||
};
|
||||
STextureFormatInfo TextureFormats[ECF_UNKNOWN] = {};
|
||||
|
||||
private:
|
||||
|
||||
COpenGL3Renderer2D* MaterialRenderer2DActive;
|
||||
|
@ -70,16 +70,6 @@ namespace video
|
||||
case EVDF_MRT_BLEND_FUNC:
|
||||
case EVDF_OCCLUSION_QUERY:
|
||||
return false;
|
||||
case EVDF_TEXTURE_COMPRESSED_DXT:
|
||||
return false; // NV Tegra need improvements here
|
||||
case EVDF_TEXTURE_COMPRESSED_PVRTC:
|
||||
return FeatureAvailable[IRR_GL_IMG_texture_compression_pvrtc];
|
||||
case EVDF_TEXTURE_COMPRESSED_PVRTC2:
|
||||
return FeatureAvailable[IRR_GL_IMG_texture_compression_pvrtc2];
|
||||
case EVDF_TEXTURE_COMPRESSED_ETC1:
|
||||
return FeatureAvailable[IRR_GL_OES_compressed_ETC1_RGB8_texture];
|
||||
case EVDF_TEXTURE_COMPRESSED_ETC2:
|
||||
return false;
|
||||
case EVDF_STENCIL_BUFFER:
|
||||
return StencilBuffer;
|
||||
default:
|
||||
@ -101,13 +91,13 @@ namespace video
|
||||
inline void irrGlCompressedTexImage2D(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border,
|
||||
GLsizei imageSize, const void* data)
|
||||
{
|
||||
glCompressedTexImage2D(target, level, internalformat, width, height, border, imageSize, data);
|
||||
os::Printer::log("Compressed textures aren't supported", ELL_ERROR);
|
||||
}
|
||||
|
||||
inline void irrGlCompressedTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
|
||||
GLenum format, GLsizei imageSize, const void* data)
|
||||
{
|
||||
glCompressedTexSubImage2D(target, level, xoffset, yoffset, width, height, format, imageSize, data);
|
||||
os::Printer::log("Compressed textures aren't supported", ELL_ERROR);
|
||||
}
|
||||
|
||||
inline void irrGlUseProgram(GLuint prog)
|
||||
|
@ -33,6 +33,24 @@ namespace video {
|
||||
assert (isVersionAtLeast(3, 2));
|
||||
initExtensionsNew();
|
||||
|
||||
TextureFormats[ECF_A1R5G5B5] = {GL_RGB5_A1, GL_BGRA, GL_UNSIGNED_SHORT_1_5_5_5_REV}; // WARNING: may not be renderable
|
||||
TextureFormats[ECF_R5G6B5] = {GL_RGB, GL_RGB, GL_UNSIGNED_SHORT_5_6_5}; // GL_RGB565 is an extension until 4.1
|
||||
TextureFormats[ECF_R8G8B8] = {GL_RGB8, GL_RGB, GL_UNSIGNED_BYTE}; // WARNING: may not be renderable
|
||||
TextureFormats[ECF_A8R8G8B8] = {GL_RGBA8, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV};
|
||||
TextureFormats[ECF_R16F] = {GL_R16F, GL_RED, GL_HALF_FLOAT};
|
||||
TextureFormats[ECF_G16R16F] = {GL_RG16F, GL_RG, GL_HALF_FLOAT};
|
||||
TextureFormats[ECF_A16B16G16R16F] = {GL_RGBA16F, GL_RGBA, GL_HALF_FLOAT};
|
||||
TextureFormats[ECF_R32F] = {GL_R32F, GL_RED, GL_FLOAT};
|
||||
TextureFormats[ECF_G32R32F] = {GL_RG32F, GL_RG, GL_FLOAT};
|
||||
TextureFormats[ECF_A32B32G32R32F] = {GL_RGBA32F, GL_RGBA, GL_FLOAT};
|
||||
TextureFormats[ECF_R8] = {GL_R8, GL_RED, GL_UNSIGNED_BYTE};
|
||||
TextureFormats[ECF_R8G8] = {GL_RG8, GL_RG, GL_UNSIGNED_BYTE};
|
||||
TextureFormats[ECF_R16] = {GL_R16, GL_RED, GL_UNSIGNED_SHORT};
|
||||
TextureFormats[ECF_R16G16] = {GL_RG16, GL_RG, GL_UNSIGNED_SHORT};
|
||||
TextureFormats[ECF_D16] = {GL_DEPTH_COMPONENT16, GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT};
|
||||
TextureFormats[ECF_D32] = {GL_DEPTH_COMPONENT32, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT}; // WARNING: may not be renderable (?!)
|
||||
TextureFormats[ECF_D24S8] = {GL_DEPTH24_STENCIL8, GL_DEPTH_STENCIL, GL_UNSIGNED_INT_24_8};
|
||||
|
||||
AnisotropicFilterSupported = isVersionAtLeast(4, 6) || queryExtension("GL_ARB_texture_filter_anisotropic") || queryExtension("GL_EXT_texture_filter_anisotropic");
|
||||
BlendMinMaxSupported = true;
|
||||
|
||||
|
@ -4,6 +4,7 @@
|
||||
|
||||
#include "Driver.h"
|
||||
#include <cassert>
|
||||
#include <CColorConverter.h>
|
||||
|
||||
namespace irr {
|
||||
namespace video {
|
||||
@ -30,6 +31,76 @@ namespace video {
|
||||
else
|
||||
initExtensionsOld();
|
||||
|
||||
if (Version.Major >= 3) {
|
||||
// NOTE floating-point formats may not be suitable for render targets.
|
||||
TextureFormats[ECF_A1R5G5B5] = {GL_RGB5_A1, GL_RGBA, GL_UNSIGNED_SHORT_5_5_5_1, CColorConverter::convert_A1R5G5B5toR5G5B5A1};
|
||||
TextureFormats[ECF_R5G6B5] = {GL_RGB565, GL_RGB, GL_UNSIGNED_SHORT_5_6_5};
|
||||
TextureFormats[ECF_R8G8B8] = {GL_RGB8, GL_RGB, GL_UNSIGNED_BYTE};
|
||||
TextureFormats[ECF_A8R8G8B8] = {GL_RGBA8, GL_RGBA, GL_UNSIGNED_BYTE, CColorConverter::convert_A8R8G8B8toA8B8G8R8};
|
||||
TextureFormats[ECF_R16F] = {GL_R16F, GL_RED, GL_HALF_FLOAT};
|
||||
TextureFormats[ECF_G16R16F] = {GL_RG16F, GL_RG, GL_HALF_FLOAT};
|
||||
TextureFormats[ECF_A16B16G16R16F] = {GL_RGBA16F, GL_RGBA, GL_HALF_FLOAT};
|
||||
TextureFormats[ECF_R32F] = {GL_R32F, GL_RED, GL_FLOAT};
|
||||
TextureFormats[ECF_G32R32F] = {GL_RG32F, GL_RG, GL_FLOAT};
|
||||
TextureFormats[ECF_A32B32G32R32F] = {GL_RGBA32F, GL_RGBA, GL_FLOAT};
|
||||
TextureFormats[ECF_R8] = {GL_R8, GL_RED, GL_UNSIGNED_BYTE};
|
||||
TextureFormats[ECF_R8G8] = {GL_RG8, GL_RG, GL_UNSIGNED_BYTE};
|
||||
TextureFormats[ECF_D16] = {GL_DEPTH_COMPONENT16, GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT};
|
||||
TextureFormats[ECF_D24S8] = {GL_DEPTH24_STENCIL8, GL_DEPTH_STENCIL, GL_UNSIGNED_INT_24_8};
|
||||
|
||||
if (FeatureAvailable[IRR_GL_EXT_texture_format_BGRA8888])
|
||||
TextureFormats[ECF_A8R8G8B8] = {GL_RGBA, GL_BGRA, GL_UNSIGNED_BYTE};
|
||||
else if (FeatureAvailable[IRR_GL_APPLE_texture_format_BGRA8888])
|
||||
TextureFormats[ECF_A8R8G8B8] = {GL_BGRA, GL_BGRA, GL_UNSIGNED_BYTE};
|
||||
|
||||
if (FeatureAvailable[IRR_GL_OES_depth32])
|
||||
TextureFormats[ECF_D32] = {GL_DEPTH_COMPONENT32, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT};
|
||||
} else {
|
||||
// NOTE These are *texture* formats. They may or may not be suitable
|
||||
// for render targets. The specs only talks on *sized* formats for the
|
||||
// latter but forbids creating textures with sized internal formats,
|
||||
// reserving them for renderbuffers.
|
||||
|
||||
static const GLenum HALF_FLOAT_OES = 0x8D61; // not equal to GL_HALF_FLOAT
|
||||
TextureFormats[ECF_A1R5G5B5] = {GL_RGBA, GL_RGBA, GL_UNSIGNED_SHORT_5_5_5_1, CColorConverter::convert_A1R5G5B5toR5G5B5A1};
|
||||
TextureFormats[ECF_R5G6B5] = {GL_RGB, GL_RGB, GL_UNSIGNED_SHORT_5_6_5};
|
||||
TextureFormats[ECF_R8G8B8] = {GL_RGB, GL_RGB, GL_UNSIGNED_BYTE};
|
||||
TextureFormats[ECF_A8R8G8B8] = {GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE, CColorConverter::convert_A8R8G8B8toA8B8G8R8};
|
||||
|
||||
if (FeatureAvailable[IRR_GL_EXT_texture_format_BGRA8888])
|
||||
TextureFormats[ECF_A8R8G8B8] = {GL_RGBA, GL_BGRA, GL_UNSIGNED_BYTE};
|
||||
else if (FeatureAvailable[IRR_GL_APPLE_texture_format_BGRA8888])
|
||||
TextureFormats[ECF_A8R8G8B8] = {GL_BGRA, GL_BGRA, GL_UNSIGNED_BYTE};
|
||||
|
||||
if (FeatureAvailable[IRR_GL_OES_texture_half_float]) {
|
||||
TextureFormats[ECF_A16B16G16R16F] = {GL_RGBA, GL_RGBA, HALF_FLOAT_OES};
|
||||
}
|
||||
if (FeatureAvailable[IRR_GL_OES_texture_float]) {
|
||||
TextureFormats[ECF_A32B32G32R32F] = {GL_RGBA, GL_RGBA, GL_FLOAT};
|
||||
}
|
||||
if (FeatureAvailable[IRR_GL_EXT_texture_rg]) {
|
||||
TextureFormats[ECF_R8] = {GL_RED, GL_RED, GL_UNSIGNED_BYTE};
|
||||
TextureFormats[ECF_R8G8] = {GL_RG, GL_RG, GL_UNSIGNED_BYTE};
|
||||
|
||||
if (FeatureAvailable[IRR_GL_OES_texture_half_float]) {
|
||||
TextureFormats[ECF_R16F] = {GL_RED, GL_RED, HALF_FLOAT_OES};
|
||||
TextureFormats[ECF_G16R16F] = {GL_RG, GL_RG, HALF_FLOAT_OES};
|
||||
}
|
||||
if (FeatureAvailable[IRR_GL_OES_texture_float]) {
|
||||
TextureFormats[ECF_R32F] = {GL_RED, GL_RED, GL_FLOAT};
|
||||
TextureFormats[ECF_G32R32F] = {GL_RG, GL_RG, GL_FLOAT};
|
||||
}
|
||||
}
|
||||
|
||||
if (FeatureAvailable[IRR_GL_OES_depth_texture]) {
|
||||
TextureFormats[ECF_D16] = {GL_DEPTH_COMPONENT, GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT};
|
||||
if (FeatureAvailable[IRR_GL_OES_depth32])
|
||||
TextureFormats[ECF_D32] = {GL_DEPTH_COMPONENT, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT};
|
||||
if (FeatureAvailable[IRR_GL_OES_packed_depth_stencil])
|
||||
TextureFormats[ECF_D24S8] = {GL_DEPTH_STENCIL, GL_DEPTH_STENCIL, GL_UNSIGNED_INT_24_8};
|
||||
}
|
||||
}
|
||||
|
||||
const bool MRTSupported = Version.Major >= 3 || queryExtension("GL_EXT_draw_buffers");
|
||||
AnisotropicFilterSupported = queryExtension("GL_EXT_texture_filter_anisotropic");
|
||||
BlendMinMaxSupported = (Version.Major >= 3) || FeatureAvailable[IRR_GL_EXT_blend_minmax];
|
||||
|
Loading…
Reference in New Issue
Block a user