code format
This commit is contained in:
@@ -1,83 +1,86 @@
|
||||
/*
|
||||
QGL RendererService
|
||||
Ivan Pelipenko peri4ko@yandex.ru
|
||||
QGL RendererService
|
||||
Ivan Pelipenko peri4ko@yandex.ru
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Lesser General Public License for more details.
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#define GL_GLEXT_PROTOTYPES
|
||||
#include <QOpenGLExtraFunctions>
|
||||
#include "renderer_service.h"
|
||||
#include "renderer.h"
|
||||
#include "qglview.h"
|
||||
|
||||
#include "glmesh.h"
|
||||
#include "qglview.h"
|
||||
#include "renderer.h"
|
||||
|
||||
#include <QOpenGLExtraFunctions>
|
||||
#include <qad_types.h>
|
||||
|
||||
using namespace QGLEngineShaders;
|
||||
|
||||
|
||||
RendererService::RendererService(Renderer * r_): r(r_) {
|
||||
line_width = 1;
|
||||
line_width = 1;
|
||||
current_action = haNoAction;
|
||||
current_handle = QFlags<HandleMesh>();
|
||||
mat_xyz.resize(3); mat_ms2.resize(3);
|
||||
color_xyz.resize(3); color_ms2.resize(3);
|
||||
const QVector3D _rot [3] = {QVector3D(0,1,0), QVector3D(-1,0,0), QVector3D(0, 0,1)};
|
||||
const QVector3D _rot2[3] = {QVector3D(0,0,0), QVector3D( 1,0,0), QVector3D(0,-1,0)};
|
||||
mat_xyz.resize(3);
|
||||
mat_ms2.resize(3);
|
||||
color_xyz.resize(3);
|
||||
color_ms2.resize(3);
|
||||
const QVector3D _rot[3] = {QVector3D(0, 1, 0), QVector3D(-1, 0, 0), QVector3D(0, 0, 1)};
|
||||
const QVector3D _rot2[3] = {QVector3D(0, 0, 0), QVector3D(1, 0, 0), QVector3D(0, -1, 0)};
|
||||
for (int i = 0; i < 3; ++i) {
|
||||
QMatrix4x4 m;
|
||||
m.rotate(90., _rot[i]);
|
||||
mat_xyz[i] = m;
|
||||
m.setToIdentity();
|
||||
if (!_rot2[i].isNull())
|
||||
m.rotate(90., _rot2[i]);
|
||||
mat_ms2[i] = m;
|
||||
color_xyz[i] = color_ms2[i] = QVector4D(0,0,0,0.8);
|
||||
color_xyz[i][i] = 1.;
|
||||
if (!_rot2[i].isNull()) m.rotate(90., _rot2[i]);
|
||||
mat_ms2[i] = m;
|
||||
color_xyz[i] = color_ms2[i] = QVector4D(0, 0, 0, 0.8);
|
||||
color_xyz[i][i] = 1.;
|
||||
}
|
||||
color_ms2[0] = (color_xyz[0] + color_xyz[1]) / 2.;
|
||||
color_ms2[1] = (color_xyz[0] + color_xyz[2]) / 2.;
|
||||
color_ms2[2] = (color_xyz[1] + color_xyz[2]) / 2.;
|
||||
axis_camera = new Camera();
|
||||
axis_camera = new Camera();
|
||||
axis_camera->setAim(QVector3D());
|
||||
axis_camera->setFOV(45.);
|
||||
axis_mesh = Primitive::arrow(12);
|
||||
axis_mesh = Primitive::arrow(12);
|
||||
size_vp_scale = size_full_scale = 1.;
|
||||
|
||||
box_mesh = Primitive::cube(0.8, 0.8, 0.8);
|
||||
box_mesh_f = Primitive::cubeFrame(0.8, 0.8, 0.8);
|
||||
omni_mesh = Primitive::ellipsoid(2, 1, 0.5);
|
||||
omni_mesh_f = Primitive::ellipsoidFrame(2, 1, 0.5);
|
||||
omni_mesh ->scalePoints(1.5);
|
||||
omni_mesh_f ->scalePoints(1.5);
|
||||
box_mesh = Primitive::cube(0.8, 0.8, 0.8);
|
||||
box_mesh_f = Primitive::cubeFrame(0.8, 0.8, 0.8);
|
||||
omni_mesh = Primitive::ellipsoid(2, 1, 0.5);
|
||||
omni_mesh_f = Primitive::ellipsoidFrame(2, 1, 0.5);
|
||||
omni_mesh->scalePoints(1.5);
|
||||
omni_mesh_f->scalePoints(1.5);
|
||||
cone_mesh = Primitive::cone(8, 0.5, 1.);
|
||||
cone_mesh_f = Primitive::coneFrame(8, 0.5, 1.);
|
||||
QMatrix4x4 mat;
|
||||
mat.translate(0,0,-1);
|
||||
cone_mesh ->transformPoints(mat);
|
||||
mat.translate(0, 0, -1);
|
||||
cone_mesh->transformPoints(mat);
|
||||
cone_mesh_f->transformPoints(mat);
|
||||
cone_mesh_f->scalePoints(1.5);
|
||||
|
||||
box_mesh ->scalePoints(1.3);
|
||||
omni_mesh ->scalePoints(1.3);
|
||||
cone_mesh ->translatePoints(0,0,0.5);
|
||||
cone_mesh ->scalePoints(1.4);
|
||||
cone_mesh ->translatePoints(0,0,-0.5);
|
||||
cone_mesh ->scalePoints(1.5);
|
||||
box_mesh->scalePoints(1.3);
|
||||
omni_mesh->scalePoints(1.3);
|
||||
cone_mesh->translatePoints(0, 0, 0.5);
|
||||
cone_mesh->scalePoints(1.4);
|
||||
cone_mesh->translatePoints(0, 0, -0.5);
|
||||
cone_mesh->scalePoints(1.5);
|
||||
|
||||
camera_mesh = Primitive::cube(1.2, 1.2, 1.2);
|
||||
mat.translate(0,0,-0.5);
|
||||
mat.translate(0, 0, -0.5);
|
||||
Mesh * m = Primitive::cone(6, 0.6, 1.);
|
||||
m->scalePoints(1.4);
|
||||
m->transformPoints(mat);
|
||||
@@ -88,34 +91,34 @@ RendererService::RendererService(Renderer * r_): r(r_) {
|
||||
m->transformPoints(mat);
|
||||
camera_mesh_f->append(m);
|
||||
|
||||
line_spot_f = Primitive::lineFrame(QVector3D(), QVector3D(0, 0, -1));
|
||||
line_camera_f = Primitive::lineFrame(QVector3D(), QVector3D(0, 0, -1));
|
||||
line_spot_f = Primitive::lineFrame(QVector3D(), QVector3D(0, 0, -1));
|
||||
line_camera_f = Primitive::lineFrame(QVector3D(), QVector3D(0, 0, -1));
|
||||
|
||||
handle_move_mesh = Primitive::arrow(12, 0.06);
|
||||
handle_ms_2_mesh = Primitive::torus(8, 12, 0.5, 0.02, 90);
|
||||
m = Primitive::disc(8, 0.5, 90);
|
||||
m = Primitive::disc(8, 0.5, 90);
|
||||
handle_ms_2_mesh->append(m);
|
||||
m->flipNormals();
|
||||
handle_ms_2_mesh->append(m);
|
||||
delete m;
|
||||
|
||||
handle_rotate_mesh = Primitive::arrow(12, 0.03);
|
||||
m = Primitive::torus(30, 12, 0.5, 0.06);
|
||||
m = Primitive::torus(30, 12, 0.5, 0.06);
|
||||
m->translatePoints(QVector3D(0., 0., 0.75));
|
||||
handle_rotate_mesh->append(m);
|
||||
delete m;
|
||||
|
||||
handle_scale_mesh = Primitive::cylinder(12, 0.03, 0.85);
|
||||
m = Primitive::ellipsoid(12, 12, 0.15);
|
||||
m = Primitive::ellipsoid(12, 12, 0.15);
|
||||
m->translatePoints(QVector3D(0., 0., 0.85));
|
||||
handle_scale_mesh->append(m);
|
||||
delete m;
|
||||
handle_scale_3_mesh = Primitive::ellipsoid(12, 12, 0.2);
|
||||
|
||||
handle_move_mesh ->scalePoints(7.5);
|
||||
handle_ms_2_mesh ->scalePoints(7.5);
|
||||
handle_rotate_mesh ->scalePoints(7.5);
|
||||
handle_scale_mesh ->scalePoints(7.5);
|
||||
handle_move_mesh->scalePoints(7.5);
|
||||
handle_ms_2_mesh->scalePoints(7.5);
|
||||
handle_rotate_mesh->scalePoints(7.5);
|
||||
handle_scale_mesh->scalePoints(7.5);
|
||||
handle_scale_3_mesh->scalePoints(7.5);
|
||||
}
|
||||
|
||||
@@ -142,23 +145,23 @@ RendererService::~RendererService() {
|
||||
|
||||
|
||||
void RendererService::init(int width, int height) {
|
||||
box_mesh ->reinit();
|
||||
box_mesh_f ->reinit();
|
||||
omni_mesh ->reinit();
|
||||
omni_mesh_f ->reinit();
|
||||
cone_mesh ->reinit();
|
||||
cone_mesh_f ->reinit();
|
||||
camera_mesh ->reinit();
|
||||
camera_mesh_f ->reinit();
|
||||
line_spot_f ->reinit();
|
||||
line_camera_f ->reinit();
|
||||
axis_mesh ->reinit();
|
||||
handle_move_mesh ->reinit();
|
||||
handle_ms_2_mesh ->reinit();
|
||||
handle_rotate_mesh ->reinit();
|
||||
handle_scale_mesh ->reinit();
|
||||
box_mesh->reinit();
|
||||
box_mesh_f->reinit();
|
||||
omni_mesh->reinit();
|
||||
omni_mesh_f->reinit();
|
||||
cone_mesh->reinit();
|
||||
cone_mesh_f->reinit();
|
||||
camera_mesh->reinit();
|
||||
camera_mesh_f->reinit();
|
||||
line_spot_f->reinit();
|
||||
line_camera_f->reinit();
|
||||
axis_mesh->reinit();
|
||||
handle_move_mesh->reinit();
|
||||
handle_ms_2_mesh->reinit();
|
||||
handle_rotate_mesh->reinit();
|
||||
handle_scale_mesh->reinit();
|
||||
handle_scale_3_mesh->reinit();
|
||||
axis_mesh ->reinit();
|
||||
axis_mesh->reinit();
|
||||
fillXYZObjects();
|
||||
axis_mesh->loadObjects(r->view, cur_objects);
|
||||
resize(width, height);
|
||||
@@ -167,15 +170,15 @@ void RendererService::init(int width, int height) {
|
||||
|
||||
void RendererService::resize(int width, int height) {
|
||||
axis_viewport = preferredIconSize(10.);
|
||||
line_width = lineThickness();
|
||||
line_width = lineThickness();
|
||||
size_vp_scale = 25. * appScale() / qMax(qMin(width, height), 1);
|
||||
//qDebug() << axis_viewport;
|
||||
// qDebug() << axis_viewport;
|
||||
}
|
||||
|
||||
|
||||
QMatrix4x4 RendererService::invariantSizeMatrix(QVector3D p, double * ret_scale) {
|
||||
QVector4D pos = QVector4D(p, 1.);
|
||||
double dist = -(v_mat * pos).z();
|
||||
double dist = -(v_mat * pos).z();
|
||||
QMatrix4x4 m;
|
||||
m.translate(pos.toVector3D());
|
||||
m.scale(dist * size_full_scale);
|
||||
@@ -209,10 +212,10 @@ void RendererService::fillXYZObjects() {
|
||||
|
||||
|
||||
void RendererService::fillOmniObjects() {
|
||||
QList<Light*> ll = r->view->scene()->lights_used.value(Light::Omni);
|
||||
QList<Light *> ll = r->view->scene()->lights_used.value(Light::Omni);
|
||||
Object o;
|
||||
cur_objects.clear();
|
||||
foreach (Light * l, ll) {
|
||||
foreach(Light * l, ll) {
|
||||
QMatrix4x4 m = invariantSizeMatrix(l->worldPos());
|
||||
m.transposed().copyDataTo(o.modelmatrix);
|
||||
o.object_id = l->id();
|
||||
@@ -225,12 +228,12 @@ void RendererService::fillAimedObjects(const ObjectBaseList & objects, Mesh * li
|
||||
Object o;
|
||||
cur_objects.clear();
|
||||
cur_aims.clear();
|
||||
QVector<QVector3D> & lv (line_mesh->vertices ());
|
||||
QVector<QVector3D> & ln (line_mesh->normals ());
|
||||
QVector<QVector2D> & lt (line_mesh->texcoords ());
|
||||
QVector< Vector2i> & lind(line_mesh->indicesLines());
|
||||
QVector<QVector3D> & lv(line_mesh->vertices());
|
||||
QVector<QVector3D> & ln(line_mesh->normals());
|
||||
QVector<QVector2D> & lt(line_mesh->texcoords());
|
||||
QVector<Vector2i> & lind(line_mesh->indicesLines());
|
||||
lv.clear();
|
||||
foreach (ObjectBase * go, objects) {
|
||||
foreach(ObjectBase * go, objects) {
|
||||
AimedObject * ao = (AimedObject *)go;
|
||||
QMatrix4x4 m;
|
||||
m = invariantSizeMatrix(ao->worldPos()) * parentRotationMatrix(ao);
|
||||
@@ -249,20 +252,25 @@ void RendererService::fillAimedObjects(const ObjectBaseList & objects, Mesh * li
|
||||
lt.resize(lv.size());
|
||||
lind.resize(lv.size() / 2);
|
||||
for (int i = 0; i < lind.size(); ++i) {
|
||||
lind[i] = Vector2i(i*2, i*2 + 1);
|
||||
lind[i] = Vector2i(i * 2, i * 2 + 1);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void RendererService::fillHandleObjects(QVector3D center, HandleMesh ids[], const QVector<QMatrix4x4> & mats, const QVector<QVector4D> & colors, QMatrix4x4 add_mat, int count) {
|
||||
void RendererService::fillHandleObjects(QVector3D center,
|
||||
HandleMesh ids[],
|
||||
const QVector<QMatrix4x4> & mats,
|
||||
const QVector<QVector4D> & colors,
|
||||
QMatrix4x4 add_mat,
|
||||
int count) {
|
||||
QMatrix4x4 m = invariantSizeMatrix(center) * add_mat;
|
||||
cur_objects.resize(count);
|
||||
for (int i = 0; i < count; ++i) {
|
||||
cur_objects[i].color = colors[i];
|
||||
QMatrix4x4 omat = m * mats[i];
|
||||
cur_objects[i].color = colors[i];
|
||||
QMatrix4x4 omat = m * mats[i];
|
||||
cur_objects[i].object_id = ids[i];
|
||||
if (current_handle.testFlag(ids[i])) {
|
||||
cur_objects[i].color = QVector4D(0,1,1,1);
|
||||
cur_objects[i].color = QVector4D(0, 1, 1, 1);
|
||||
}
|
||||
omat.transposed().copyDataTo(cur_objects[i].modelmatrix);
|
||||
}
|
||||
@@ -275,7 +283,7 @@ bool RendererService::calculateCenter() {
|
||||
selection_center = sol[0]->worldPos();
|
||||
if (sol.size() > 1) {
|
||||
Box3D bb;
|
||||
foreach (ObjectBase * o, sol) {
|
||||
foreach(ObjectBase * o, sol) {
|
||||
o->calculateBoundingBox();
|
||||
bb |= o->boundingBox();
|
||||
}
|
||||
@@ -286,8 +294,7 @@ bool RendererService::calculateCenter() {
|
||||
axis_mat = QMatrix4x4();
|
||||
if ((sol.size() == 1)) {
|
||||
if (current_action == haMove) {
|
||||
if (sol[0]->isAimSelected())
|
||||
selection_center = ((AimedObject*)sol[0])->worldAim();
|
||||
if (sol[0]->isAimSelected()) selection_center = ((AimedObject *)sol[0])->worldAim();
|
||||
} else {
|
||||
axis_mat = parentRotationMatrix(sol[0]);
|
||||
}
|
||||
@@ -301,9 +308,21 @@ void RendererService::drawCurrentHandleObjects() {
|
||||
if (calculateCenter()) {
|
||||
HandleMesh ids[3];
|
||||
switch (current_action) {
|
||||
case haMove : ids[0] = hmMoveX ; ids[1] = hmMoveY ; ids[2] = hmMoveZ ; break;
|
||||
case haRotate: ids[0] = hmRotateX; ids[1] = hmRotateY; ids[2] = hmRotateZ; break;
|
||||
case haScale : ids[0] = hmScaleX ; ids[1] = hmScaleY ; ids[2] = hmScaleZ ; break;
|
||||
case haMove:
|
||||
ids[0] = hmMoveX;
|
||||
ids[1] = hmMoveY;
|
||||
ids[2] = hmMoveZ;
|
||||
break;
|
||||
case haRotate:
|
||||
ids[0] = hmRotateX;
|
||||
ids[1] = hmRotateY;
|
||||
ids[2] = hmRotateZ;
|
||||
break;
|
||||
case haScale:
|
||||
ids[0] = hmScaleX;
|
||||
ids[1] = hmScaleY;
|
||||
ids[2] = hmScaleZ;
|
||||
break;
|
||||
default: break;
|
||||
}
|
||||
fillHandleObjects(selection_center, ids, mat_xyz, color_xyz, axis_mat);
|
||||
@@ -317,8 +336,16 @@ void RendererService::drawCurrentHandleObjects() {
|
||||
}
|
||||
if (current_action == haMove || current_action == haScale) {
|
||||
switch (current_action) {
|
||||
case haMove : ids[0] = hmMoveXY ; ids[1] = hmMoveXZ ; ids[2] = hmMoveYZ ; break;
|
||||
case haScale : ids[0] = hmScaleXY ; ids[1] = hmScaleXZ ; ids[2] = hmScaleYZ ; break;
|
||||
case haMove:
|
||||
ids[0] = hmMoveXY;
|
||||
ids[1] = hmMoveXZ;
|
||||
ids[2] = hmMoveYZ;
|
||||
break;
|
||||
case haScale:
|
||||
ids[0] = hmScaleXY;
|
||||
ids[1] = hmScaleXZ;
|
||||
ids[2] = hmScaleYZ;
|
||||
break;
|
||||
default: break;
|
||||
}
|
||||
hm = handle_ms_2_mesh;
|
||||
@@ -328,8 +355,10 @@ void RendererService::drawCurrentHandleObjects() {
|
||||
hm->draw(r->view, 3);
|
||||
if (current_action == haScale) {
|
||||
hm = handle_scale_3_mesh;
|
||||
QVector<QMatrix4x4> mv; mv.resize(1);
|
||||
QVector<QVector4D> cv; cv.fill(QVector4D(1, 1, 0.5, 1), 1);
|
||||
QVector<QMatrix4x4> mv;
|
||||
mv.resize(1);
|
||||
QVector<QVector4D> cv;
|
||||
cv.fill(QVector4D(1, 1, 0.5, 1), 1);
|
||||
ids[0] = hmMaxScale;
|
||||
fillHandleObjects(selection_center, ids, mv, cv, axis_mat, 1);
|
||||
hm->loadObjects(r->view, cur_objects);
|
||||
@@ -360,7 +389,6 @@ void RendererService::drawLights() {
|
||||
box_mesh->loadObjects(v, cur_aims);
|
||||
box_mesh->loadSelections(v, rs.cur_selections_);
|
||||
box_mesh->draw(v, cur_aims.size());
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -387,7 +415,6 @@ void RendererService::drawLightsFrame(QColor color) {
|
||||
box_mesh_f->loadObjects(v, cur_aims);
|
||||
box_mesh_f->loadSelections(v, rs.cur_selections_);
|
||||
box_mesh_f->draw(v, cur_aims.size());
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -405,7 +432,6 @@ void RendererService::drawCameras() {
|
||||
box_mesh->loadObjects(v, cur_aims);
|
||||
box_mesh->loadSelections(v, rs.cur_selections_);
|
||||
box_mesh->draw(v, cur_aims.size());
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -426,7 +452,6 @@ void RendererService::drawCamerasFrame(QColor color) {
|
||||
box_mesh_f->loadObjects(v, cur_aims);
|
||||
box_mesh_f->loadSelections(v, rs.cur_selections_);
|
||||
box_mesh_f->draw(v, cur_aims.size());
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -439,9 +464,9 @@ void RendererService::setObjectsColor(QVector<Object> & ol, QColor col) {
|
||||
|
||||
void RendererService::renderService() {
|
||||
QOpenGLShaderProgram * prog = 0;
|
||||
QOpenGLExtraFunctions * f = r->view;
|
||||
size_full_scale = tan(r->view->camera()->FOV() / 2. * deg2rad) * size_vp_scale;
|
||||
v_mat = r->view->camera()->fullViewMatrix();
|
||||
QOpenGLExtraFunctions * f = r->view;
|
||||
size_full_scale = tan(r->view->camera()->FOV() / 2. * deg2rad) * size_vp_scale;
|
||||
v_mat = r->view->camera()->fullViewMatrix();
|
||||
f->glEnable(GL_MULTISAMPLE);
|
||||
glEnableDepth();
|
||||
f->glClear(GL_DEPTH_BUFFER_BIT);
|
||||
@@ -460,14 +485,13 @@ void RendererService::renderService() {
|
||||
prog->setUniformValue("z_offset", -1.E-2f);
|
||||
drawLightsFrame(Qt::black);
|
||||
drawCamerasFrame(Qt::black);
|
||||
|
||||
}
|
||||
if (r->bindShader(Renderer::srServiceLine, &prog)) {
|
||||
r->setUniformCamera(prog, r->view->camera());
|
||||
line_object.color = QColor2QVector(Qt::white);
|
||||
line_spot_f ->loadObject(f, line_object);
|
||||
line_spot_f->loadObject(f, line_object);
|
||||
line_camera_f->loadObject(f, line_object);
|
||||
line_spot_f ->draw(f, 1);
|
||||
line_spot_f->draw(f, 1);
|
||||
line_camera_f->draw(f, 1);
|
||||
}
|
||||
glEnable(GL_CULL_FACE);
|
||||
@@ -488,7 +512,6 @@ void RendererService::renderService() {
|
||||
r->setUniformCamera(prog, axis_camera, true, axis_viewport);
|
||||
axis_mesh->draw(f, 3);
|
||||
f->glViewport(0, 0, r->view->width(), r->view->height());
|
||||
|
||||
}
|
||||
f->glDisable(GL_MULTISAMPLE);
|
||||
}
|
||||
@@ -496,9 +519,9 @@ void RendererService::renderService() {
|
||||
|
||||
Mesh * RendererService::currentHandleMesh() {
|
||||
switch (current_action) {
|
||||
case haMove : return handle_move_mesh;
|
||||
case haMove: return handle_move_mesh;
|
||||
case haRotate: return handle_rotate_mesh;
|
||||
case haScale : return handle_scale_mesh;
|
||||
case haScale: return handle_scale_mesh;
|
||||
default: break;
|
||||
}
|
||||
return 0;
|
||||
|
||||
Reference in New Issue
Block a user