mirror of
https://github.com/ConjureETS/LOG750-LAB2.git
synced 2026-03-24 03:21:19 +00:00
[WIP] sooo cloooose
This commit is contained in:
parent
9c79eca90d
commit
36020ec131
@ -6,6 +6,7 @@ uniform sampler2D tex;
|
|||||||
uniform float skyMult;
|
uniform float skyMult;
|
||||||
uniform bool drawTextures;
|
uniform bool drawTextures;
|
||||||
uniform bool isLightSource;
|
uniform bool isLightSource;
|
||||||
|
uniform bool isPickingMode;
|
||||||
uniform vec3 pointLight[3];
|
uniform vec3 pointLight[3];
|
||||||
uniform vec4 pointLightCol[3];
|
uniform vec4 pointLightCol[3];
|
||||||
|
|
||||||
@ -64,12 +65,16 @@ void
|
|||||||
main()
|
main()
|
||||||
{
|
{
|
||||||
vec4 texColor;
|
vec4 texColor;
|
||||||
|
|
||||||
if(drawTextures) {
|
if(drawTextures) {
|
||||||
texColor = texture(tex, texCoords);
|
texColor = texture(tex, texCoords);
|
||||||
} else {
|
} else {
|
||||||
texColor = ifColor;
|
texColor = ifColor;
|
||||||
}
|
}
|
||||||
if(isLightSource) {
|
|
||||||
|
if(isPickingMode){
|
||||||
|
fColor = ifColor;
|
||||||
|
} else if(isLightSource) {
|
||||||
fColor = texColor;
|
fColor = texColor;
|
||||||
} else if(isSky) {
|
} else if(isSky) {
|
||||||
fColor = skyMult * normalize(texColor*texColor*texColor*2/1.41)*2;
|
fColor = skyMult * normalize(texColor*texColor*texColor*2/1.41)*2;
|
||||||
|
|||||||
@ -3,12 +3,13 @@ uniform mat4 mvMatrix;
|
|||||||
uniform mat4 projMatrix;
|
uniform mat4 projMatrix;
|
||||||
uniform mat3 normalMatrix;
|
uniform mat3 normalMatrix;
|
||||||
uniform vec3 lDirection;
|
uniform vec3 lDirection;
|
||||||
uniform bool isLightSource;
|
|
||||||
|
|
||||||
uniform vec4 color;
|
uniform vec4 color;
|
||||||
|
|
||||||
uniform bool isSky;
|
uniform bool isSky;
|
||||||
uniform bool isPhong;
|
uniform bool isPhong;
|
||||||
|
uniform bool isLightSource;
|
||||||
|
uniform bool isPickingMode;
|
||||||
uniform vec3 pointLight[3];
|
uniform vec3 pointLight[3];
|
||||||
|
|
||||||
in vec4 vPosition;
|
in vec4 vPosition;
|
||||||
@ -80,7 +81,7 @@ main()
|
|||||||
|
|
||||||
ifColor = color;
|
ifColor = color;
|
||||||
|
|
||||||
if(!isPhong && !isSky && !isLightSource) {
|
if(!isPickingMode && !isPhong && !isSky && !isLightSource) {
|
||||||
ifColor = calcDirLight(vEyeCoord, fPosition, fNormal)
|
ifColor = calcDirLight(vEyeCoord, fPosition, fNormal)
|
||||||
+ calcPointLight(vEyeCoord, fPosition, fNormal, 0)
|
+ calcPointLight(vEyeCoord, fPosition, fNormal, 0)
|
||||||
+ calcPointLight(vEyeCoord, fPosition, fNormal, 1)
|
+ calcPointLight(vEyeCoord, fPosition, fNormal, 1)
|
||||||
|
|||||||
@ -100,9 +100,8 @@ void Viewer::cleanup()
|
|||||||
void Viewer::drawSkybox()
|
void Viewer::drawSkybox()
|
||||||
{
|
{
|
||||||
// Use the Skybox Shaders
|
// Use the Skybox Shaders
|
||||||
//skyboxRenderShaderProgram->bind();
|
m_program->bind();
|
||||||
s_texture->bind();
|
s_texture->bind();
|
||||||
|
|
||||||
// Get projection and camera transformations
|
// Get projection and camera transformations
|
||||||
QMatrix4x4 projectionMatrix;
|
QMatrix4x4 projectionMatrix;
|
||||||
QMatrix4x4 modelViewMatrix;
|
QMatrix4x4 modelViewMatrix;
|
||||||
@ -111,7 +110,7 @@ void Viewer::drawSkybox()
|
|||||||
|
|
||||||
// Increase size of skybox
|
// Increase size of skybox
|
||||||
|
|
||||||
modelViewMatrix.scale(101);
|
modelViewMatrix.scale(100);
|
||||||
|
|
||||||
float colorMult = 0.2 + std::fabs(0.8 * cos(std::fmod(angle_mult * frame + 300, 360) / 360 * M_PI));
|
float colorMult = 0.2 + std::fabs(0.8 * cos(std::fmod(angle_mult * frame + 300, 360) / 360 * M_PI));
|
||||||
|
|
||||||
@ -120,18 +119,17 @@ void Viewer::drawSkybox()
|
|||||||
m_program->setUniformValue(m_isSkyLoc, true);
|
m_program->setUniformValue(m_isSkyLoc, true);
|
||||||
m_program->setUniformValue(m_drawTextLoc, true);
|
m_program->setUniformValue(m_drawTextLoc, true);
|
||||||
m_program->setUniformValue(m_isLightLoc, false);
|
m_program->setUniformValue(m_isLightLoc, false);
|
||||||
|
m_program->setUniformValue(m_colorLocation, *(new QColor(0, 0, 0, 0)));
|
||||||
|
|
||||||
int faces = floor(numVerticesCube/6);
|
glCullFace( GL_FRONT );
|
||||||
for(int i = 0; i < faces; i++){ // 6 vertexes par face
|
glBindVertexArray(m_VAOs[VAO_Cube]);
|
||||||
glBindVertexArray(m_VAOs[VAO_Cube]);
|
glDrawArrays(GL_TRIANGLES, 0, 36);
|
||||||
|
|
||||||
glDrawArrays(GL_TRIANGLES, i*6, 6);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Viewer::draw()
|
void Viewer::draw()
|
||||||
{
|
{
|
||||||
drawSkybox();
|
drawSkybox();
|
||||||
|
glCullFace( GL_BACK );
|
||||||
|
|
||||||
// Bind our vertex/fragment shaders
|
// Bind our vertex/fragment shaders
|
||||||
m_program->bind();
|
m_program->bind();
|
||||||
@ -142,18 +140,6 @@ void Viewer::draw()
|
|||||||
camera()->getProjectionMatrix(projectionMatrix);
|
camera()->getProjectionMatrix(projectionMatrix);
|
||||||
camera()->getModelViewMatrix(modelViewMatrix);
|
camera()->getModelViewMatrix(modelViewMatrix);
|
||||||
|
|
||||||
// Prepare a transformation stack
|
|
||||||
|
|
||||||
// stack<QMatrix4x4> modelStack;
|
|
||||||
|
|
||||||
//modelViewMatrix.rotate(45, 0, 1, 0);
|
|
||||||
// uncomment this and the cube translation in init()
|
|
||||||
// to see the cube spin
|
|
||||||
/*rot = QQuaternion::fromAxisAndAngle(1, 0, 1, 90/60 * frame);
|
|
||||||
modelViewMatrix.rotate(rot);
|
|
||||||
projectionMatrix.translate(0, -5, 0);
|
|
||||||
projectionMatrix.rotate(15, 1, 0, 0);//*/
|
|
||||||
|
|
||||||
modelViewMatrix.rotate(30,0,1,0);
|
modelViewMatrix.rotate(30,0,1,0);
|
||||||
|
|
||||||
m_program->setUniformValue(m_projMatrixLocation, projectionMatrix);
|
m_program->setUniformValue(m_projMatrixLocation, projectionMatrix);
|
||||||
@ -162,7 +148,7 @@ void Viewer::draw()
|
|||||||
// Adjust sun position
|
// Adjust sun position
|
||||||
|
|
||||||
float rotAngle = std::fmod(angle_mult * frame, 360);
|
float rotAngle = std::fmod(angle_mult * frame, 360);
|
||||||
//sunRotate.rotate(rotAngle, 1, 0, 0);
|
sunRotate.rotate(rotAngle, 1, 0, 0);
|
||||||
|
|
||||||
m_program->setUniformValue(m_lDirLoc, (modelViewMatrix * sunRotate * sun));
|
m_program->setUniformValue(m_lDirLoc, (modelViewMatrix * sunRotate * sun));
|
||||||
selection->transform.setToIdentity();
|
selection->transform.setToIdentity();
|
||||||
@ -183,12 +169,10 @@ void Viewer::draw()
|
|||||||
void Viewer::mouseMoveEvent(QMouseEvent* e) {
|
void Viewer::mouseMoveEvent(QMouseEvent* e) {
|
||||||
//cout << "Viewer::mouseMoveEvent(QMouseEvent* e)" << endl;
|
//cout << "Viewer::mouseMoveEvent(QMouseEvent* e)" << endl;
|
||||||
// Normal QGLViewer behavior.
|
// Normal QGLViewer behavior.
|
||||||
QGLViewer::mouseMoveEvent(e);
|
QGLViewer::mouseMoveEvent(e);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Viewer::mousePressEvent(QMouseEvent* e) {
|
void Viewer::mousePressEvent(QMouseEvent* e) {
|
||||||
// Auto Return, but old code left in as reference
|
|
||||||
|
|
||||||
// TODO: figure out how to get this weird offset ↓↓ frame position maybe?
|
// TODO: figure out how to get this weird offset ↓↓ frame position maybe?
|
||||||
int x = this->x() + e->x() + 10;
|
int x = this->x() + e->x() + 10;
|
||||||
int y = this->parentWidget()->height() - e->y() + 21;
|
int y = this->parentWidget()->height() - e->y() + 21;
|
||||||
@ -197,7 +181,7 @@ void Viewer::mousePressEvent(QMouseEvent* e) {
|
|||||||
Shape* selectedShape = pickGeom(x, y);
|
Shape* selectedShape = pickGeom(x, y);
|
||||||
// OpenGL coords start at the window's bottom-left, not the frame's. ugh.
|
// OpenGL coords start at the window's bottom-left, not the frame's. ugh.
|
||||||
|
|
||||||
QGLViewer::mousePressEvent(e);
|
QGLViewer::mousePressEvent(e);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Viewer::deselect(){
|
void Viewer::deselect(){
|
||||||
@ -216,7 +200,10 @@ void Viewer::deselect(){
|
|||||||
}
|
}
|
||||||
|
|
||||||
void Viewer::mouseReleaseEvent(QMouseEvent* e) {
|
void Viewer::mouseReleaseEvent(QMouseEvent* e) {
|
||||||
|
m_program->bind();
|
||||||
|
m_program->setUniformValue(m_isPickingModeLoc, false);
|
||||||
//cout << "Viewer::mouseReleaseEvent(QMouseEvent* e)" << endl;
|
//cout << "Viewer::mouseReleaseEvent(QMouseEvent* e)" << endl;
|
||||||
|
//m_program->setUniformValue(m_isPickingModeLoc, false);
|
||||||
QGLViewer::mouseReleaseEvent(e);
|
QGLViewer::mouseReleaseEvent(e);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -366,11 +353,15 @@ void Viewer::initShaders()
|
|||||||
if ((m_c2Loc = m_program->uniformLocation("pointLightCol[1]")) < 0)
|
if ((m_c2Loc = m_program->uniformLocation("pointLightCol[1]")) < 0)
|
||||||
qDebug() << "Unable to find m_shader location for" << "pointLightCol[1]";
|
qDebug() << "Unable to find m_shader location for" << "pointLightCol[1]";
|
||||||
|
|
||||||
if ((m_c3Loc = m_program->uniformLocation("pointLightCol[2]")) < 0)
|
if ((m_c3Loc = m_program->uniformLocation("pointLightCol[2]")) < 0)
|
||||||
qDebug() << "Unable to find m_shader location for" << "pointLightCol[2]";
|
qDebug() << "Unable to find m_shader location for" << "pointLightCol[2]";
|
||||||
|
|
||||||
|
if ((m_isPickingModeLoc = m_program->uniformLocation("isPickingMode")) < 0)
|
||||||
|
qDebug() << "Unable to find m_shader location for" << "isPickingMode" << m_program->log();
|
||||||
|
|
||||||
m_program->setUniformValue(m_isPhongLoc, true);
|
m_program->setUniformValue(m_isPhongLoc, true);
|
||||||
m_program->setUniformValue(m_drawTextLoc, false);
|
m_program->setUniformValue(m_drawTextLoc, false);
|
||||||
|
m_program->setUniformValue(m_isPickingModeLoc, false);
|
||||||
|
|
||||||
|
|
||||||
s_texture = new QOpenGLTexture(QImage("src/data/skybox.jpg"));/*/
|
s_texture = new QOpenGLTexture(QImage("src/data/skybox.jpg"));/*/
|
||||||
@ -384,9 +375,9 @@ void Viewer::initGeometries()
|
|||||||
{
|
{
|
||||||
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||||
glEnable( GL_BLEND );
|
glEnable( GL_BLEND );
|
||||||
//glEnable( GL_CULL_FACE );
|
glEnable( GL_CULL_FACE );
|
||||||
glFrontFace( GL_CCW );
|
glFrontFace( GL_CCW );
|
||||||
//glCullFace( GL_BACK );
|
glCullFace( GL_BACK );
|
||||||
glClearColor(0.0,0.0,0.0,0.0);
|
glClearColor(0.0,0.0,0.0,0.0);
|
||||||
|
|
||||||
// Create our VertexArrays Objects and VertexBuffer Objects
|
// Create our VertexArrays Objects and VertexBuffer Objects
|
||||||
@ -599,50 +590,53 @@ void Viewer::visit(Cube &s)
|
|||||||
QMatrix4x4 modelViewMatrix = modelStack.top() * QMatrix4x4(s.transform);
|
QMatrix4x4 modelViewMatrix = modelStack.top() * QMatrix4x4(s.transform);
|
||||||
|
|
||||||
int faces = floor(numVerticesCube/6);
|
int faces = floor(numVerticesCube/6);
|
||||||
for(int i = 0; i < faces; i++){ // 6 vertexes par face
|
glBindVertexArray(m_VAOs[VAO_Cube]);
|
||||||
glBindVertexArray(m_VAOs[VAO_Cube]);
|
|
||||||
m_program->setUniformValue(m_isSkyLoc, false);
|
|
||||||
m_program->setUniformValue(m_mvMatrixLocation, modelViewMatrix);
|
|
||||||
m_program->setUniformValue(m_normalMatrixLoc, modelViewMatrix.normalMatrix());
|
|
||||||
m_program->setUniformValue(m_colorLocation, s.getColor());
|
|
||||||
m_program->setUniformValue(m_drawTextLoc, true);
|
|
||||||
m_program->setUniformValue(m_isLightLoc, false);
|
|
||||||
|
|
||||||
glDrawArrays(GL_TRIANGLES, i*6, 6);
|
for(int i =0; i<faces; i++){
|
||||||
}
|
m_program->setUniformValue(m_isSkyLoc, false);
|
||||||
|
m_program->setUniformValue(m_mvMatrixLocation, modelViewMatrix);
|
||||||
|
m_program->setUniformValue(m_normalMatrixLoc, modelViewMatrix.normalMatrix());
|
||||||
|
m_program->setUniformValue(m_colorLocation, *(new QColor(255, 255, 0)));
|
||||||
|
m_program->setUniformValue(m_drawTextLoc, true);
|
||||||
|
m_program->setUniformValue(m_isLightLoc, false);
|
||||||
|
|
||||||
|
//glDrawArrays(GL_TRIANGLES, i*6, 6);
|
||||||
|
}
|
||||||
|
glDrawArrays(GL_TRIANGLES, 0, 36);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void Viewer::visit(Sphere &s)
|
void Viewer::visit(Sphere &s)
|
||||||
{
|
{
|
||||||
|
return;
|
||||||
// std::cout << "Sphere found";
|
// std::cout << "Sphere found";
|
||||||
QMatrix4x4 modelViewMatrix = modelStack.top() * QMatrix4x4(s.transform);
|
QMatrix4x4 modelViewMatrix = modelStack.top() * QMatrix4x4(s.transform);
|
||||||
|
|
||||||
glBindVertexArray(m_VAOs[VAO_Sphere]);
|
glBindVertexArray(m_VAOs[VAO_Sphere]);
|
||||||
m_program->setUniformValue(m_isSkyLoc, false);
|
m_program->setUniformValue(m_isSkyLoc, false);
|
||||||
m_program->setUniformValue(m_mvMatrixLocation, modelViewMatrix);
|
m_program->setUniformValue(m_mvMatrixLocation, modelViewMatrix);
|
||||||
m_program->setUniformValue(m_normalMatrixLoc, modelViewMatrix.normalMatrix());
|
m_program->setUniformValue(m_normalMatrixLoc, modelViewMatrix.normalMatrix());
|
||||||
m_program->setUniformValue(m_colorLocation, s.getColor());
|
m_program->setUniformValue(m_colorLocation, s.getColor());
|
||||||
m_program->setUniformValue(m_drawTextLoc, false);
|
m_program->setUniformValue(m_drawTextLoc, false);
|
||||||
m_program->setUniformValue(m_isLightLoc, true);
|
m_program->setUniformValue(m_isLightLoc, true);
|
||||||
|
|
||||||
// This will save the current position of this light ball as the next point
|
// This will save the current position of this light ball as the next point
|
||||||
// This means point lights are technically 1 frame behind
|
// This means point lights are technically 1 frame behind
|
||||||
|
|
||||||
QVector3D point = QVector3D(0,0,0);
|
QVector3D point = QVector3D(0,0,0);
|
||||||
|
|
||||||
point = modelViewMatrix * point;
|
point = modelViewMatrix * point;
|
||||||
|
|
||||||
|
|
||||||
int pointLocs[3] = {m_point1Loc, m_point2Loc, m_point3Loc};
|
int pointLocs[3] = {m_point1Loc, m_point2Loc, m_point3Loc};
|
||||||
int pointCLocs[3] = {m_c1Loc, m_c2Loc, m_c3Loc};
|
int pointCLocs[3] = {m_c1Loc, m_c2Loc, m_c3Loc};
|
||||||
|
|
||||||
m_program->setUniformValue(pointLocs[currentPoint], point);
|
m_program->setUniformValue(pointLocs[currentPoint], point);
|
||||||
m_program->setUniformValue(pointCLocs[currentPoint], s.getColor());
|
m_program->setUniformValue(pointCLocs[currentPoint], s.getColor());
|
||||||
|
|
||||||
currentPoint = (currentPoint + 1) % 3;
|
currentPoint = (currentPoint + 1) % 3;
|
||||||
|
|
||||||
glDrawElements(GL_TRIANGLES, numTriSphere * 3, GL_UNSIGNED_INT, 0);
|
glDrawElements(GL_TRIANGLES, numTriSphere*3, GL_UNSIGNED_INT, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Viewer::visit(SceneGroup &s)
|
void Viewer::visit(SceneGroup &s)
|
||||||
@ -680,6 +674,10 @@ void Viewer::changeColor(QColor c){
|
|||||||
}
|
}
|
||||||
|
|
||||||
Shape* Viewer::pickGeom(int x, int y){
|
Shape* Viewer::pickGeom(int x, int y){
|
||||||
|
|
||||||
|
m_program->bind();
|
||||||
|
m_program->setUniformValue(m_isPickingModeLoc, true);
|
||||||
|
|
||||||
QMap<QRgb, Shape*> mapColorToShape;
|
QMap<QRgb, Shape*> mapColorToShape;
|
||||||
QColor c;
|
QColor c;
|
||||||
QRgb startColor = 0xFF0001; // alpha must be 100%, glReadPixels doesn't resturn alpha
|
QRgb startColor = 0xFF0001; // alpha must be 100%, glReadPixels doesn't resturn alpha
|
||||||
@ -691,8 +689,6 @@ Shape* Viewer::pickGeom(int x, int y){
|
|||||||
*/
|
*/
|
||||||
QOpenGLShaderProgram *lastshader = m_program;
|
QOpenGLShaderProgram *lastshader = m_program;
|
||||||
|
|
||||||
//colorPickerShaderProgram->bind();
|
|
||||||
|
|
||||||
std::cout << "Iterating through " << root.getChildren()->size() << "items"<<endl;
|
std::cout << "Iterating through " << root.getChildren()->size() << "items"<<endl;
|
||||||
|
|
||||||
for(int i = 0, l = root.getChildren()->size(); i<l; i++)
|
for(int i = 0, l = root.getChildren()->size(); i<l; i++)
|
||||||
@ -716,7 +712,11 @@ Shape* Viewer::pickGeom(int x, int y){
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
update();
|
glFlush();
|
||||||
|
drawSkybox();
|
||||||
|
modelStack.pop();
|
||||||
|
draw();
|
||||||
|
glFinish();
|
||||||
|
|
||||||
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
|
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
|
||||||
|
|
||||||
@ -732,15 +732,13 @@ Shape* Viewer::pickGeom(int x, int y){
|
|||||||
}
|
}
|
||||||
im->save("./screenshot.bmp");//*/
|
im->save("./screenshot.bmp");//*/
|
||||||
|
|
||||||
glReadPixels(x, y, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, pixelData);
|
glReadPixels(x, y, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, pixelData);
|
||||||
QColor* pickedColor = new QColor(pixelData[0], pixelData[1], pixelData[2]);
|
QColor* pickedColor = new QColor(pixelData[0], pixelData[1], pixelData[2]);
|
||||||
unsigned int pickedInt = pickedColor->rgb();
|
unsigned int pickedInt = pickedColor->rgb();
|
||||||
Shape* pickedShape = mapColorToShape.value(pickedInt - (pickedInt % 6) + 1);
|
Shape* pickedShape = mapColorToShape.value(pickedInt - (pickedInt % 6) + 1);
|
||||||
std::cout << "Picked Color: " << pickedColor->red() << " " << pickedColor->green() << " " << pickedColor->blue() << " " << pickedColor->alpha() << endl;
|
std::cout << "Picked Color: " << pickedColor->red() << " " << pickedColor->green() << " " << pickedColor->blue() << " " << pickedColor->alpha() << endl;
|
||||||
std::cout << "Picked Shape: " << pickedShape << endl;
|
std::cout << "Picked Shape: " << pickedShape << endl;
|
||||||
|
|
||||||
|
m_program->setUniformValue(m_isPickingModeLoc, true);
|
||||||
|
|
||||||
//lastshader->bind();
|
|
||||||
return pickedShape;
|
return pickedShape;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -99,8 +99,8 @@ private:
|
|||||||
int m_isSkyLoc;
|
int m_isSkyLoc;
|
||||||
int m_lDirLoc;
|
int m_lDirLoc;
|
||||||
int m_skyMultLoc;
|
int m_skyMultLoc;
|
||||||
int m_drawTextLoc;
|
int m_drawTextLoc;
|
||||||
int m_isLightLoc;
|
int m_isLightLoc;
|
||||||
|
|
||||||
int m_point1Loc;
|
int m_point1Loc;
|
||||||
int m_point2Loc;
|
int m_point2Loc;
|
||||||
@ -110,7 +110,9 @@ private:
|
|||||||
int m_c2Loc;
|
int m_c2Loc;
|
||||||
int m_c3Loc;
|
int m_c3Loc;
|
||||||
|
|
||||||
float angle_mult;
|
int m_isPickingModeLoc;
|
||||||
|
|
||||||
|
float angle_mult;
|
||||||
|
|
||||||
QOpenGLTexture *s_texture;
|
QOpenGLTexture *s_texture;
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user