Finally cubemap is working
This commit is contained in:
parent
ef92c70ae8
commit
84ee2dc70c
@ -59,7 +59,8 @@ protected:
|
||||
cardinal TexID;
|
||||
cardinal NormTexID;
|
||||
|
||||
TTriangleList TriangleList;
|
||||
//TTriangleList TriangleList;
|
||||
VertexDataStruct vertexDataStruct;
|
||||
|
||||
mat3 ShaderRotateMatrix;
|
||||
vec3 ShaderTranslateVector;
|
||||
|
@ -75,6 +75,10 @@ extern PFNGLBUFFERSUBDATAPROC glBufferSubData;
|
||||
extern PFNGLMAPBUFFERPROC glMapBuffer;
|
||||
extern PFNGLUNMAPBUFFERPROC glUnmapBuffer;
|
||||
|
||||
extern PFNGLGENVERTEXARRAYSPROC glGenVertexArrays;
|
||||
extern PFNGLBINDVERTEXARRAYPROC glBindVertexArray;
|
||||
extern PFNGLDELETEVERTEXARRAYSPROC glDeleteVertexArray;
|
||||
|
||||
//=========================================
|
||||
//============ Frame buffer ===============
|
||||
//=========================================
|
||||
|
@ -20,6 +20,48 @@
|
||||
namespace SE
|
||||
{
|
||||
|
||||
class VBOHolder {
|
||||
GLuint Buffer;
|
||||
|
||||
public:
|
||||
VBOHolder();
|
||||
|
||||
VBOHolder(const VBOHolder& v) = delete;
|
||||
|
||||
VBOHolder& operator=(const VBOHolder& v) = delete;
|
||||
|
||||
~VBOHolder();
|
||||
|
||||
GLuint getBuffer();
|
||||
};
|
||||
|
||||
class VAOHolder {
|
||||
GLuint vao;
|
||||
|
||||
public:
|
||||
VAOHolder();
|
||||
|
||||
VAOHolder(const VAOHolder& v) = delete;
|
||||
|
||||
VAOHolder& operator=(const VAOHolder& v) = delete;
|
||||
|
||||
~VAOHolder();
|
||||
|
||||
GLuint getBuffer();
|
||||
};
|
||||
|
||||
struct VertexDataStruct
|
||||
{
|
||||
std::vector<vec3> PositionData;
|
||||
std::vector<vec2> TexCoordData;
|
||||
|
||||
std::shared_ptr<VAOHolder> vao;
|
||||
std::shared_ptr<VBOHolder> positionVBO;
|
||||
std::shared_ptr<VBOHolder> texCoordVBO;
|
||||
|
||||
void RefreshVBO();
|
||||
};
|
||||
|
||||
struct T2DQuad
|
||||
{
|
||||
vec3 VertexCoord[4];
|
||||
@ -58,6 +100,7 @@ public:
|
||||
};
|
||||
|
||||
|
||||
|
||||
#ifdef TARGET_WIN32
|
||||
|
||||
class VBOObject //Must stay in shared ptr only!
|
||||
@ -75,6 +118,7 @@ public:
|
||||
};
|
||||
|
||||
|
||||
void DrawVertexDataStruct(const VertexDataStruct& vertexDataStruct);
|
||||
|
||||
class TTriangleList : public TTriangleListAncestor //Implementation differs for Windows and Android
|
||||
{
|
||||
|
@ -33,6 +33,11 @@ protected:
|
||||
cardinal BkgTexID;
|
||||
std::string BkgShaderName;
|
||||
|
||||
float FogBeginDistance;
|
||||
float FogEndDistance;
|
||||
vec4 FogColor;
|
||||
|
||||
|
||||
void CalcCamPosVec();
|
||||
|
||||
virtual void DrawQuad(const T2DQuad& quad) = 0;
|
||||
@ -52,6 +57,7 @@ public:
|
||||
void SetPerspectiveProjectionMatrix(float angle, float aspect, float zNear, float zFar);
|
||||
void PushPerspectiveProjectionMatrix(float angle, float aspect, float zNear, float zFar);
|
||||
|
||||
void SetGLCamAngleView();
|
||||
void SetGLCamView();
|
||||
void SetGlIdentityView();
|
||||
void SetGlPosXView();
|
||||
@ -87,6 +93,14 @@ public:
|
||||
|
||||
void DrawBackground();
|
||||
|
||||
float GetFogBeginDistance();
|
||||
float GetFogEndDistance();
|
||||
vec4 GetFogColor();
|
||||
|
||||
|
||||
void SetFogBeginDistance(float distance);
|
||||
void SetFogEndDistance(float distance);
|
||||
|
||||
};
|
||||
|
||||
} //namespace SE
|
||||
|
@ -22,11 +22,6 @@ protected:
|
||||
bool IsCameraTransparentToLand; //To make it work you must setup LandToCalcCollision
|
||||
TSimpleLandClass* LandToCalcCollision;
|
||||
|
||||
float FogBeginDistance;
|
||||
float FogEndDistance;
|
||||
vec4 FogColor;
|
||||
|
||||
|
||||
//Other data:
|
||||
|
||||
float ShadowClampValue;
|
||||
@ -45,9 +40,6 @@ public:
|
||||
float GetShadowClampValue();
|
||||
void SetShadowClampValue(float shadowClampValue);
|
||||
|
||||
float GetFogBeginDistance();
|
||||
float GetFogEndDistance();
|
||||
vec4 GetFogColor();
|
||||
|
||||
void DrawTriangleList(const TTriangleList& triangleList);
|
||||
|
||||
|
@ -56,6 +56,7 @@ private:
|
||||
cardinal NormTexID;
|
||||
|
||||
//For VBO:
|
||||
/*
|
||||
std::vector<word> IndexArr;
|
||||
TVBOLandVertex VBOLandVertexArr;
|
||||
|
||||
@ -64,7 +65,8 @@ private:
|
||||
cardinal NormBuffer;
|
||||
cardinal TangentBuffer;
|
||||
cardinal BinormBuffer;
|
||||
cardinal TexcoordBuffer;
|
||||
cardinal TexcoordBuffer;*/
|
||||
VertexDataStruct vertexDataStruct;
|
||||
|
||||
void CreateVBO();
|
||||
void FreeVBO();
|
||||
|
@ -87,7 +87,7 @@ public:
|
||||
cardinal AddTexture(const std::string& fileName, std::string texName = ""); //Adds path to resources to the filename then call previous one
|
||||
cardinal AddTextureFromUserdata(const std::string& fileName, std::string texName = ""); //Same as above but checks if file is created in user data
|
||||
|
||||
cardinal AddCubemapTexture(std::string filename[6]); // "posx.bmp","negx.bmp","posy.bmp","negy.bmp","posz.bmp","negz.bmp"
|
||||
cardinal AddCubemapTexture(std::array<std::string, 6> filename); // "posx.bmp","negx.bmp","posy.bmp","negy.bmp","posz.bmp","negz.bmp"
|
||||
|
||||
|
||||
cardinal AddEmptyTexture(const std::string& texName, cardinal width, cardinal height);
|
||||
|
@ -70,7 +70,7 @@ public:
|
||||
tvec3<TYPENAME1>& operator-=(const tvec3<TYPENAME1>& vc);
|
||||
tvec3<TYPENAME1> operator+(const tvec3<TYPENAME1>& a) const;
|
||||
tvec3<TYPENAME1> operator-(const tvec3<TYPENAME1>& a) const;
|
||||
tvec3<TYPENAME1>& operator-();
|
||||
tvec3<TYPENAME1> operator-();
|
||||
tvec3<TYPENAME1>& operator*=(TYPENAME1 c);
|
||||
tvec3<TYPENAME1> operator*(const tmat3<TYPENAME1>& mt) const; //MultRowMatrix()
|
||||
};
|
||||
@ -440,13 +440,14 @@ inline tvec3<TYPENAME1> tvec3<TYPENAME1>::operator-(const tvec3<TYPENAME1>& a) c
|
||||
}
|
||||
|
||||
template<typename TYPENAME1>
|
||||
inline tvec3<TYPENAME1>& tvec3<TYPENAME1>::operator-()
|
||||
tvec3<TYPENAME1> tvec3<TYPENAME1>::operator-()
|
||||
{
|
||||
v[0] = -v[0];
|
||||
v[1] = -v[1];
|
||||
v[2] = -v[2];
|
||||
tvec3<TYPENAME1> result;
|
||||
result.v[0] = -v[0];
|
||||
result.v[1] = -v[1];
|
||||
result.v[2] = -v[2];
|
||||
|
||||
return *this;
|
||||
return result;
|
||||
}
|
||||
|
||||
template<typename TYPENAME1>
|
||||
|
@ -554,7 +554,7 @@ void TAnimModel::RecalcVertexPos()
|
||||
}
|
||||
|
||||
//LiteModel.VertexArr[i] = px;
|
||||
LiteModel.TriangleList.Data.Vec3CoordArr[CONST_STRING_POSITION_ATTRIB][i] = px;
|
||||
//LiteModel.TriangleList.Data.Vec3CoordArr[CONST_STRING_POSITION_ATTRIB][i] = px;
|
||||
|
||||
/*
|
||||
//Normal
|
||||
@ -578,14 +578,14 @@ void TAnimModel::RecalcVertexPos()
|
||||
void TAnimModel::SaveVertexInfoToBuf()
|
||||
{
|
||||
|
||||
CopyVertexArr = LiteModel.TriangleList.Data.Vec3CoordArr[CONST_STRING_POSITION_ATTRIB];
|
||||
//CopyVertexArr = LiteModel.TriangleList.Data.Vec3CoordArr[CONST_STRING_POSITION_ATTRIB];
|
||||
|
||||
AnimList->SaveBoneSystemToBuf();
|
||||
}
|
||||
void TAnimModel::LoadVertexInfoFromBuf()
|
||||
{
|
||||
|
||||
LiteModel.TriangleList.Data.Vec3CoordArr[CONST_STRING_POSITION_ATTRIB] = CopyVertexArr;
|
||||
//LiteModel.TriangleList.Data.Vec3CoordArr[CONST_STRING_POSITION_ATTRIB] = CopyVertexArr;
|
||||
|
||||
AnimList->LoadBoneSystemFromBuf();
|
||||
}
|
||||
@ -597,8 +597,8 @@ bool TAnimModel::LoadModel(const std::string& modelName)
|
||||
return false;
|
||||
|
||||
|
||||
CopyVertexArr.resize(LiteModel.TriangleList.Data.Vec3CoordArr[CONST_STRING_POSITION_ATTRIB].size());
|
||||
CopyVertexArr = LiteModel.TriangleList.Data.Vec3CoordArr[CONST_STRING_POSITION_ATTRIB];
|
||||
//CopyVertexArr.resize(LiteModel.TriangleList.Data.Vec3CoordArr[CONST_STRING_POSITION_ATTRIB].size());
|
||||
//CopyVertexArr = LiteModel.TriangleList.Data.Vec3CoordArr[CONST_STRING_POSITION_ATTRIB];
|
||||
|
||||
AnimList = ResourceManager->ModelAnimManager[modelName];
|
||||
|
||||
|
@ -117,13 +117,17 @@ bool TLiteModel::LoadModel(const std::string& s)
|
||||
else
|
||||
NormTexID = 0;
|
||||
|
||||
vertexDataStruct.PositionData = res.VertexArr;
|
||||
vertexDataStruct.TexCoordData = res.TexCoordArr;
|
||||
|
||||
vertexDataStruct.RefreshVBO();
|
||||
/*
|
||||
TriangleList.Data.Vec3CoordArr[CONST_STRING_POSITION_ATTRIB] = res.VertexArr;
|
||||
TriangleList.Data.Vec3CoordArr[CONST_STRING_NORMAL_ATTRIB] = res.NormalArr;
|
||||
TriangleList.Data.Vec3CoordArr[CONST_STRING_TANGENT_ATTRIB] = res.TangentArr;
|
||||
TriangleList.Data.Vec3CoordArr[CONST_STRING_BINORMAL_ATTRIB] = res.BinormalArr;
|
||||
TriangleList.Data.Vec2CoordArr[CONST_STRING_TEXCOORD_ATTRIB] = res.TexCoordArr;
|
||||
|
||||
*/
|
||||
Loaded = true;
|
||||
|
||||
return true;
|
||||
@ -133,10 +137,10 @@ void TLiteModel::FreeModel()
|
||||
{
|
||||
Loaded = false;
|
||||
|
||||
TriangleList.Data.Vec3CoordArr.clear();
|
||||
TriangleList.Data.Vec2CoordArr.clear();
|
||||
//TriangleList.Data.Vec3CoordArr.clear();
|
||||
//TriangleList.Data.Vec2CoordArr.clear();
|
||||
#ifdef TARGET_WIN32
|
||||
TriangleList.VertBufferArr.clear();
|
||||
//TriangleList.VertBufferArr.clear();
|
||||
#endif
|
||||
TriangleCount = 0;
|
||||
TexID = 0;
|
||||
@ -151,7 +155,8 @@ void TLiteModel::UpdateVBO()
|
||||
|
||||
CheckGlError();
|
||||
|
||||
TriangleList.RefreshBuffer();
|
||||
//TriangleList.RefreshBuffer();
|
||||
vertexDataStruct.RefreshVBO();
|
||||
|
||||
CheckGlError();
|
||||
|
||||
@ -159,7 +164,7 @@ void TLiteModel::UpdateVBO()
|
||||
|
||||
void TLiteModel::DrawImmediate()
|
||||
{
|
||||
|
||||
/*
|
||||
#ifdef TARGET_WIN32
|
||||
|
||||
if (Loaded)
|
||||
@ -211,7 +216,7 @@ void TLiteModel::DrawImmediate()
|
||||
RenderUniform1i(CONST_STRING_NORMALMAPEXISTS_UNIFORM, 1);
|
||||
|
||||
}
|
||||
#endif
|
||||
#endif*/
|
||||
}
|
||||
|
||||
void TLiteModel::DrawVBO()
|
||||
@ -230,7 +235,14 @@ void TLiteModel::DrawVBO()
|
||||
glActiveTexture(GL_TEXTURE0);
|
||||
glBindTexture(GL_TEXTURE_2D,TexID);
|
||||
|
||||
Renderer->DrawTriangleList(TriangleList);
|
||||
EnableVertexAttribArray("vPosition");
|
||||
EnableVertexAttribArray("vTexCoord");
|
||||
|
||||
//Renderer->DrawTriangleList(TriangleList);
|
||||
DrawVertexDataStruct(vertexDataStruct);
|
||||
|
||||
DisableVertexAttribArray("vPosition");
|
||||
DisableVertexAttribArray("vTexCoord");
|
||||
|
||||
RenderUniform1i(CONST_STRING_NORMALMAPEXISTS_UNIFORM, 1);
|
||||
|
||||
@ -244,7 +256,7 @@ void TLiteModel::MoveModel(const vec3& v)
|
||||
{
|
||||
for (cardinal i = 0; i < TriangleCount * 3; i++)
|
||||
{
|
||||
TriangleList.Data.Vec3CoordArr[CONST_STRING_POSITION_ATTRIB][i] += v;
|
||||
//TriangleList.Data.Vec3CoordArr[CONST_STRING_POSITION_ATTRIB][i] += v;
|
||||
}
|
||||
}
|
||||
|
||||
@ -253,10 +265,10 @@ void TLiteModel::RotateModel(const mat3& r)
|
||||
|
||||
for (cardinal i = 0; i < TriangleCount * 3; i++)
|
||||
{
|
||||
TriangleList.Data.Vec3CoordArr[CONST_STRING_POSITION_ATTRIB][i] = r * TriangleList.Data.Vec3CoordArr[CONST_STRING_POSITION_ATTRIB][i];
|
||||
TriangleList.Data.Vec3CoordArr[CONST_STRING_NORMAL_ATTRIB][i] = r * TriangleList.Data.Vec3CoordArr[CONST_STRING_NORMAL_ATTRIB][i];
|
||||
TriangleList.Data.Vec3CoordArr[CONST_STRING_TANGENT_ATTRIB][i] = r * TriangleList.Data.Vec3CoordArr[CONST_STRING_TANGENT_ATTRIB][i];
|
||||
TriangleList.Data.Vec3CoordArr[CONST_STRING_BINORMAL_ATTRIB][i] = r * TriangleList.Data.Vec3CoordArr[CONST_STRING_BINORMAL_ATTRIB][i];
|
||||
//TriangleList.Data.Vec3CoordArr[CONST_STRING_POSITION_ATTRIB][i] = r * TriangleList.Data.Vec3CoordArr[CONST_STRING_POSITION_ATTRIB][i];
|
||||
//TriangleList.Data.Vec3CoordArr[CONST_STRING_NORMAL_ATTRIB][i] = r * TriangleList.Data.Vec3CoordArr[CONST_STRING_NORMAL_ATTRIB][i];
|
||||
//TriangleList.Data.Vec3CoordArr[CONST_STRING_TANGENT_ATTRIB][i] = r * TriangleList.Data.Vec3CoordArr[CONST_STRING_TANGENT_ATTRIB][i];
|
||||
//TriangleList.Data.Vec3CoordArr[CONST_STRING_BINORMAL_ATTRIB][i] = r * TriangleList.Data.Vec3CoordArr[CONST_STRING_BINORMAL_ATTRIB][i];
|
||||
}
|
||||
}
|
||||
|
||||
@ -265,7 +277,7 @@ void TLiteModel::ScaleModel(float s)
|
||||
|
||||
for (cardinal i = 0; i < TriangleCount * 3; i++)
|
||||
{
|
||||
TriangleList.Data.Vec3CoordArr[CONST_STRING_POSITION_ATTRIB][i] *= s;
|
||||
//TriangleList.Data.Vec3CoordArr[CONST_STRING_POSITION_ATTRIB][i] *= s;
|
||||
}
|
||||
|
||||
}
|
||||
@ -276,9 +288,9 @@ void TLiteModel::ScaleModel(const vec3& s)
|
||||
|
||||
for (cardinal i = 0; i < TriangleCount * 3; i++)
|
||||
{
|
||||
TriangleList.Data.Vec3CoordArr[CONST_STRING_POSITION_ATTRIB][i].v[0] *= s.v[0];
|
||||
TriangleList.Data.Vec3CoordArr[CONST_STRING_POSITION_ATTRIB][i].v[1] *= s.v[1];
|
||||
TriangleList.Data.Vec3CoordArr[CONST_STRING_POSITION_ATTRIB][i].v[2] *= s.v[2];
|
||||
//TriangleList.Data.Vec3CoordArr[CONST_STRING_POSITION_ATTRIB][i].v[0] *= s.v[0];
|
||||
//TriangleList.Data.Vec3CoordArr[CONST_STRING_POSITION_ATTRIB][i].v[1] *= s.v[1];
|
||||
//TriangleList.Data.Vec3CoordArr[CONST_STRING_POSITION_ATTRIB][i].v[2] *= s.v[2];
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -66,6 +66,10 @@ PFNGLBUFFERSUBDATAPROC glBufferSubData = NULL;
|
||||
PFNGLMAPBUFFERPROC glMapBuffer = NULL;
|
||||
PFNGLUNMAPBUFFERPROC glUnmapBuffer = NULL;
|
||||
|
||||
PFNGLGENVERTEXARRAYSPROC glGenVertexArrays = NULL;
|
||||
PFNGLBINDVERTEXARRAYPROC glBindVertexArray = NULL;
|
||||
PFNGLDELETEVERTEXARRAYSPROC glDeleteVertexArray = NULL;
|
||||
|
||||
//=========================================
|
||||
//============ Frame buffer ===============
|
||||
//=========================================
|
||||
|
@ -2,6 +2,88 @@
|
||||
|
||||
namespace SE
|
||||
{
|
||||
VBOHolder::VBOHolder()
|
||||
{
|
||||
glGenBuffers(1, &Buffer);
|
||||
}
|
||||
|
||||
VBOHolder::~VBOHolder()
|
||||
{
|
||||
glDeleteBuffers(1, &Buffer);
|
||||
}
|
||||
|
||||
GLuint VBOHolder::getBuffer()
|
||||
{
|
||||
return Buffer;
|
||||
}
|
||||
|
||||
VAOHolder::VAOHolder()
|
||||
{
|
||||
#ifndef EMSCRIPTEN
|
||||
glGenVertexArrays(1, &vao);
|
||||
#endif
|
||||
}
|
||||
|
||||
VAOHolder::~VAOHolder()
|
||||
{
|
||||
#ifndef EMSCRIPTEN
|
||||
glDeleteVertexArray(1, &vao);
|
||||
#endif
|
||||
}
|
||||
|
||||
GLuint VAOHolder::getBuffer()
|
||||
{
|
||||
return vao;
|
||||
}
|
||||
|
||||
void VertexDataStruct::RefreshVBO()
|
||||
{
|
||||
//Check if main thread, check if data is not empty...
|
||||
|
||||
#ifndef EMSCRIPTEN
|
||||
if (!vao)
|
||||
{
|
||||
vao = std::make_shared<VAOHolder>();
|
||||
}
|
||||
|
||||
glBindVertexArray(vao->getBuffer());
|
||||
#endif
|
||||
if (!positionVBO)
|
||||
{
|
||||
positionVBO = std::make_shared<VBOHolder>();
|
||||
}
|
||||
|
||||
glBindBuffer(GL_ARRAY_BUFFER, positionVBO->getBuffer());
|
||||
|
||||
glBufferData(GL_ARRAY_BUFFER, PositionData.size() * 12, &PositionData[0], GL_STATIC_DRAW);
|
||||
|
||||
if (!texCoordVBO)
|
||||
{
|
||||
texCoordVBO = std::make_shared<VBOHolder>();
|
||||
}
|
||||
|
||||
glBindBuffer(GL_ARRAY_BUFFER, texCoordVBO->getBuffer());
|
||||
|
||||
glBufferData(GL_ARRAY_BUFFER, TexCoordData.size() * 8, &TexCoordData[0], GL_STATIC_DRAW);
|
||||
|
||||
}
|
||||
|
||||
void DrawVertexDataStruct(const VertexDataStruct& vertexDataStruct)
|
||||
{
|
||||
static const std::string vTexCoord("vTexCoord");
|
||||
static const std::string vPosition("vPosition");
|
||||
|
||||
//Check if main thread, check if data is not empty...
|
||||
glBindBuffer(GL_ARRAY_BUFFER, vertexDataStruct.texCoordVBO->getBuffer());
|
||||
VertexAttribPointer2fv(vTexCoord, 0, NULL);
|
||||
|
||||
glBindBuffer(GL_ARRAY_BUFFER, vertexDataStruct.positionVBO->getBuffer());
|
||||
VertexAttribPointer3fv(vPosition, 0, NULL);
|
||||
|
||||
glDrawArrays(GL_TRIANGLES, 0, static_cast<GLsizei>(vertexDataStruct.PositionData.size()));
|
||||
|
||||
}
|
||||
|
||||
|
||||
#ifdef TARGET_WIN32
|
||||
|
||||
|
@ -13,6 +13,9 @@ TSalmonRendererInterface::TSalmonRendererInterface()
|
||||
, CamDist(0.0f)
|
||||
, CamShift(ZeroVec3)
|
||||
, GlobalShadowAreaHalfSize(CONST_DEFAULT_GLOBAL_SHADOW_AREA_HALFSIZE)
|
||||
, FogBeginDistance(CONST_DEFAULT_FOG_BEGIN_DISTANCE)
|
||||
, FogEndDistance(CONST_DEFAULT_FOG_END_DISTANCE)
|
||||
, FogColor(CONST_DEFAULT_FOG_COLOR)
|
||||
{
|
||||
ProjectionMatrixStack.push(IdentityMatrix4);
|
||||
|
||||
@ -54,8 +57,8 @@ void TSalmonRendererInterface::SetUniforms()
|
||||
//RenderUniform1f(CONST_STRING_SHADOWCLAMPVALUE_UNIFORM, GetShadowClampValue());
|
||||
//RenderUniform1i(CONST_STRING_ACTIVELIGHTCOUNT_UNIFORM, ResourceManager->LightManager.GetActiveLightCount());
|
||||
|
||||
//RenderUniform1f(CONST_STRING_FOG_BEGIN_DISTANCE_UNIFORM, GetFogBeginDistance());
|
||||
//RenderUniform1f(CONST_STRING_FOG_END_DISTANCE_UNIFORM, GetFogEndDistance());
|
||||
RenderUniform1f(CONST_STRING_FOG_BEGIN_DISTANCE_UNIFORM, GetFogBeginDistance());
|
||||
RenderUniform1f(CONST_STRING_FOG_END_DISTANCE_UNIFORM, GetFogEndDistance());
|
||||
//RenderUniform4fv(CONST_STRING_FOG_COLOR_UNIFORM, GetFogColor().v);
|
||||
|
||||
RenderUniform3fv(CONST_STRING_CAMPOS_UNIFORM, GetCamPos().v);
|
||||
@ -171,7 +174,31 @@ void TSalmonRendererInterface::PushPerspectiveProjectionMatrix(float angle, floa
|
||||
|
||||
|
||||
|
||||
void TSalmonRendererInterface::SetGLCamAngleView()
|
||||
{
|
||||
/*
|
||||
glLoadIdentity();
|
||||
glTranslatef(0.0f, 0.0f, -CamDist);
|
||||
glRotatef(CamPhi*180.0f/pi, 1.0f, 0.0f, 0.0f);
|
||||
glRotatef(CamAlpha*180.0f/pi, 0.0f, 1.0f, 0.0f);
|
||||
|
||||
//TODO
|
||||
glTranslatef(-CamShift.v[0], -CamShift.v[1], -CamShift.v[2]);
|
||||
|
||||
glGetFloatv(GL_MODELVIEW_MATRIX,CamModelViewMatrix.m);
|
||||
|
||||
CamInversedModelViewMatrix = InverseModelViewMatrix(CamModelViewMatrix);
|
||||
|
||||
RenderUniform3fv(CONST_STRING_CAMPOS_UNIFORM,CamPos.v);*/
|
||||
LoadIdentity();
|
||||
RotateMatrix(vec4(1.f * sin(CamPhi / 2.f), 0.f, 0.f, 1.f * cos(CamPhi / 2.f)));
|
||||
RotateMatrix(vec4(0.f, 1.f * sin(CamAlpha / 2.f), 0.f, 1.f * cos(CamAlpha / 2.f)));
|
||||
|
||||
CamModelViewMatrix = ModelviewMatrixStack.top();
|
||||
CamInversedModelViewMatrix = InverseModelViewMatrix(CamModelViewMatrix);
|
||||
|
||||
SetUniforms();
|
||||
}
|
||||
|
||||
void TSalmonRendererInterface::SetGLCamView()
|
||||
{
|
||||
@ -189,7 +216,6 @@ void TSalmonRendererInterface::SetGLCamView()
|
||||
CamInversedModelViewMatrix = InverseModelViewMatrix(CamModelViewMatrix);
|
||||
|
||||
RenderUniform3fv(CONST_STRING_CAMPOS_UNIFORM,CamPos.v);*/
|
||||
|
||||
LoadIdentity();
|
||||
TranslateMatrix(vec3(0.0f, 0.0f, -CamDist));
|
||||
RotateMatrix(vec4(1.f * sin(CamPhi/2.f), 0.f, 0.f, 1.f * cos(CamPhi/2.f)));
|
||||
@ -234,11 +260,8 @@ void TSalmonRendererInterface::SetGlPosXView()
|
||||
CamInversedModelViewMatrix = InverseModelViewMatrix(CamModelViewMatrix);*/
|
||||
|
||||
LoadIdentity();
|
||||
|
||||
RotateMatrix(vec4(0.f, 1.f * sin(pi / 4.f), 0.f, 1.f * cos(pi / 4.f)));
|
||||
RotateMatrix(vec4(1.f * sin(pi / 2.f), 0.f, 0.f, 1.f * cos(pi / 2.f)));
|
||||
|
||||
TranslateMatrix(-CamShift);
|
||||
TranslateMatrix(-CamPos);
|
||||
|
||||
CamModelViewMatrix = ModelviewMatrixStack.top();
|
||||
CamInversedModelViewMatrix = InverseModelViewMatrix(CamModelViewMatrix);
|
||||
@ -260,11 +283,8 @@ void TSalmonRendererInterface::SetGlNegXView()
|
||||
CamInversedModelViewMatrix = InverseModelViewMatrix(CamModelViewMatrix);*/
|
||||
|
||||
LoadIdentity();
|
||||
|
||||
RotateMatrix(vec4(0.f, -1.f * sin(pi / 4.f), 0.f, 1.f * cos(pi / 4.f)));
|
||||
RotateMatrix(vec4(1.f * sin(pi / 2.f), 0.f, 0.f, 1.f * cos(pi / 2.f)));
|
||||
|
||||
TranslateMatrix(-CamShift);
|
||||
TranslateMatrix(-CamPos);
|
||||
|
||||
CamModelViewMatrix = ModelviewMatrixStack.top();
|
||||
CamInversedModelViewMatrix = InverseModelViewMatrix(CamModelViewMatrix);
|
||||
@ -283,10 +303,10 @@ void TSalmonRendererInterface::SetGlPosYView()
|
||||
|
||||
CamInversedModelViewMatrix = InverseModelViewMatrix(CamModelViewMatrix);*/
|
||||
|
||||
LoadIdentity();
|
||||
RotateMatrix(vec4(-1.f * sin(pi / 4.f), 0.f, 0.f, 1.f * cos(pi / 4.f)));
|
||||
|
||||
TranslateMatrix(-CamShift);
|
||||
LoadIdentity();
|
||||
RotateMatrix(vec4(1.f * sin(pi / 4.f), 0.0f, 0.f, 1.f * cos(pi / 4.f)));
|
||||
TranslateMatrix(-CamPos);
|
||||
|
||||
CamModelViewMatrix = ModelviewMatrixStack.top();
|
||||
CamInversedModelViewMatrix = InverseModelViewMatrix(CamModelViewMatrix);
|
||||
@ -307,9 +327,8 @@ void TSalmonRendererInterface::SetGlNegYView()
|
||||
CamInversedModelViewMatrix = InverseModelViewMatrix(CamModelViewMatrix);*/
|
||||
|
||||
LoadIdentity();
|
||||
RotateMatrix(vec4(1.f * sin(pi / 4.f), 0.f, 0.f, 1.f * cos(pi / 4.f)));
|
||||
|
||||
TranslateMatrix(-CamShift);
|
||||
RotateMatrix(vec4(-1.f * sin(pi / 4.f), 0.0f, 0.f, 1.f * cos(pi / 4.f)));
|
||||
TranslateMatrix(-CamPos);
|
||||
|
||||
CamModelViewMatrix = ModelviewMatrixStack.top();
|
||||
CamInversedModelViewMatrix = InverseModelViewMatrix(CamModelViewMatrix);
|
||||
@ -330,12 +349,14 @@ void TSalmonRendererInterface::SetGlPosZView()
|
||||
CamInversedModelViewMatrix = InverseModelViewMatrix(CamModelViewMatrix);
|
||||
*/
|
||||
|
||||
LoadIdentity();
|
||||
TranslateMatrix(-CamPos);
|
||||
|
||||
/*LoadIdentity();
|
||||
|
||||
RotateMatrix(vec4(0.f, 1.f * sin(pi / 2.f), 0.f, 1.f * cos(pi / 2.f)));
|
||||
RotateMatrix(vec4(0.f, 0.f, 1.f * sin(pi / 2.f), 1.f * cos(pi / 2.f)));
|
||||
|
||||
TranslateMatrix(-CamShift);
|
||||
TranslateMatrix(-CamShift);*/
|
||||
|
||||
CamModelViewMatrix = ModelviewMatrixStack.top();
|
||||
CamInversedModelViewMatrix = InverseModelViewMatrix(CamModelViewMatrix);
|
||||
@ -356,9 +377,8 @@ void TSalmonRendererInterface::SetGlNegZView()
|
||||
|
||||
LoadIdentity();
|
||||
|
||||
RotateMatrix(vec4(0.f, 0.f, 1.f * sin(pi / 2.f), 1.f * cos(pi / 2.f)));
|
||||
|
||||
TranslateMatrix(-CamShift);
|
||||
RotateMatrix(vec4(0.f, 1.f * sin(pi / 2.f), 0.f, 1.f * cos(pi / 2.f)));
|
||||
TranslateMatrix(-CamPos);
|
||||
|
||||
CamModelViewMatrix = ModelviewMatrixStack.top();
|
||||
CamInversedModelViewMatrix = InverseModelViewMatrix(CamModelViewMatrix);
|
||||
@ -770,6 +790,9 @@ void TSalmonRendererInterface::SwitchToCubemapBuffer(const std::string& frameNam
|
||||
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, Frame.FrameBuffer);
|
||||
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_CUBE_MAP_POSITIVE_X + cubeSide, Frame.TexID, 0);
|
||||
//PopProjectionMatrix();
|
||||
//PushPerspectiveProjectionMatrix(pi / 2, 1.0, 1, 1000);
|
||||
//glViewport(0, 0, Frame.Width, Frame.Height);
|
||||
/*
|
||||
glMatrixMode(GL_PROJECTION);
|
||||
glLoadIdentity();
|
||||
@ -777,7 +800,7 @@ void TSalmonRendererInterface::SwitchToCubemapBuffer(const std::string& frameNam
|
||||
glViewport(0, 0, Frame.Width, Frame.Height);
|
||||
glMatrixMode(GL_MODELVIEW);*/
|
||||
|
||||
SetPerspectiveProjectionMatrix(90, 1, 1, 100);
|
||||
SetPerspectiveProjectionMatrix(pi / 2, 1, 1, 100);
|
||||
|
||||
SetFrameViewport(frameName);
|
||||
|
||||
@ -874,6 +897,33 @@ void TSalmonRendererInterface::DrawBackground()
|
||||
PopShader();
|
||||
}
|
||||
}
|
||||
vec4 TSalmonRendererInterface::GetFogColor()
|
||||
{
|
||||
return FogColor;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
float TSalmonRendererInterface::GetFogBeginDistance()
|
||||
{
|
||||
return FogBeginDistance;
|
||||
}
|
||||
|
||||
float TSalmonRendererInterface::GetFogEndDistance()
|
||||
{
|
||||
return FogEndDistance;
|
||||
}
|
||||
|
||||
void TSalmonRendererInterface::SetFogBeginDistance(float distance)
|
||||
{
|
||||
FogBeginDistance = distance;
|
||||
}
|
||||
|
||||
void TSalmonRendererInterface::SetFogEndDistance(float distance)
|
||||
{
|
||||
FogEndDistance = distance;
|
||||
}
|
||||
|
||||
|
||||
} //namespace SE
|
||||
|
@ -13,9 +13,6 @@ namespace SE
|
||||
|
||||
TSalmonRenderer::TSalmonRenderer() :
|
||||
ShadowClampValue(0.0f),
|
||||
FogBeginDistance(CONST_DEFAULT_FOG_BEGIN_DISTANCE),
|
||||
FogEndDistance(CONST_DEFAULT_FOG_END_DISTANCE),
|
||||
FogColor(CONST_DEFAULT_FOG_COLOR),
|
||||
LandToCalcCollision(NULL),
|
||||
IsCameraTransparentToLand(true)
|
||||
{
|
||||
@ -51,6 +48,10 @@ bool TSalmonRenderer::BindOpenGLFunctions()
|
||||
glMapBuffer = (PFNGLMAPBUFFERPROC) wglGetProcAddress("glMapBuffer");
|
||||
glUnmapBuffer = (PFNGLUNMAPBUFFERPROC) wglGetProcAddress("glUnmapBuffer");
|
||||
|
||||
glGenVertexArrays = (PFNGLGENVERTEXARRAYSPROC)wglGetProcAddress("glGenVertexArrays");
|
||||
glBindVertexArray = (PFNGLBINDVERTEXARRAYPROC)wglGetProcAddress("glBindVertexArray");
|
||||
glDeleteVertexArray = (PFNGLDELETEVERTEXARRAYSPROC)wglGetProcAddress("glDeleteVertexArray");
|
||||
|
||||
glCreateProgram = (PFNGLCREATEPROGRAMPROC) wglGetProcAddress("glCreateProgram");
|
||||
glDeleteProgram = (PFNGLDELETEPROGRAMPROC) wglGetProcAddress("glDeleteProgram");
|
||||
glLinkProgram = (PFNGLLINKPROGRAMPROC) wglGetProcAddress("glLinkProgram");
|
||||
@ -293,22 +294,6 @@ void TSalmonRenderer::SetShadowClampValue(float shadowClampValue)
|
||||
}
|
||||
|
||||
|
||||
float TSalmonRenderer::GetFogBeginDistance()
|
||||
{
|
||||
return FogBeginDistance;
|
||||
}
|
||||
|
||||
float TSalmonRenderer::GetFogEndDistance()
|
||||
{
|
||||
return FogEndDistance;
|
||||
}
|
||||
|
||||
vec4 TSalmonRenderer::GetFogColor()
|
||||
{
|
||||
return FogColor;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void TSalmonRenderer::DrawTriangleList(const TTriangleList& triangleList)
|
||||
|
@ -68,15 +68,103 @@ TSimpleLandClass::~TSimpleLandClass()
|
||||
|
||||
void TSimpleLandClass::CreateVBO()
|
||||
{
|
||||
IndexArr.resize(6*(Width-1)*(Height-1));
|
||||
|
||||
int i, j, k, k_up, k_right, k_right_up;
|
||||
|
||||
vertexDataStruct.PositionData.clear();
|
||||
vertexDataStruct.TexCoordData.clear();
|
||||
|
||||
for (i = 0; i < Height - 1; i++)
|
||||
{
|
||||
for (j = 0; j < Width - 1; j++)
|
||||
{
|
||||
k = j + i * Width;
|
||||
k_right = (j + 1) + i * Width;
|
||||
k_up = j + (i + 1) * Width;
|
||||
k_right_up = (j + 1) + (i + 1) * Width;
|
||||
|
||||
float tx0 = float(j) / (Width - 1);
|
||||
float ty0 = float(i) / (Height - 1);
|
||||
|
||||
float tx1 = float(j + 1) / (Width - 1);
|
||||
float ty1 = float(i + 1) / (Height - 1);
|
||||
|
||||
vertexDataStruct.PositionData.push_back(VertexMatrix[k].pos);
|
||||
vertexDataStruct.PositionData.push_back(VertexMatrix[k_right].pos);
|
||||
vertexDataStruct.PositionData.push_back(VertexMatrix[k_up].pos);
|
||||
|
||||
|
||||
vertexDataStruct.PositionData.push_back(VertexMatrix[k_right_up].pos);
|
||||
vertexDataStruct.PositionData.push_back(VertexMatrix[k_up].pos);
|
||||
vertexDataStruct.PositionData.push_back(VertexMatrix[k_right].pos);
|
||||
|
||||
vertexDataStruct.TexCoordData.push_back({ tx0, ty0 });
|
||||
vertexDataStruct.TexCoordData.push_back({ tx1, ty0 });
|
||||
vertexDataStruct.TexCoordData.push_back({ tx0, ty1 });
|
||||
|
||||
|
||||
vertexDataStruct.TexCoordData.push_back({ tx1, ty1 });
|
||||
vertexDataStruct.TexCoordData.push_back({ tx0, ty1 });
|
||||
vertexDataStruct.TexCoordData.push_back({ tx1, ty0 });
|
||||
|
||||
/*
|
||||
glBegin(GL_TRIANGLES);
|
||||
glNormal3fv(VertexMatrix[k].norm.v);
|
||||
VertexAttrib3fv(CONST_STRING_TANGENT_ATTRIB, VertexMatrix[k].tangent.v);
|
||||
VertexAttrib3fv(CONST_STRING_BINORMAL_ATTRIB, VertexMatrix[k].binorm.v);
|
||||
VertexAttrib3fv(CONST_STRING_TEXCOORD_ATTRIB, &std::array<float, 2>{ tx0, ty0 }[0]);
|
||||
glVertex3fv(VertexMatrix[k].pos.v);
|
||||
|
||||
glNormal3fv(VertexMatrix[k_right].norm.v);
|
||||
VertexAttrib3fv(CONST_STRING_TANGENT_ATTRIB, VertexMatrix[k_right].tangent.v);
|
||||
VertexAttrib3fv(CONST_STRING_BINORMAL_ATTRIB, VertexMatrix[k_right].binorm.v);
|
||||
VertexAttrib3fv(CONST_STRING_TEXCOORD_ATTRIB, &std::array<float, 2>{ tx1, ty0 }[0]);
|
||||
glVertex3fv(VertexMatrix[k_right].pos.v);
|
||||
|
||||
glNormal3fv(VertexMatrix[k_up].norm.v);
|
||||
VertexAttrib3fv(CONST_STRING_TANGENT_ATTRIB, VertexMatrix[k_up].tangent.v);
|
||||
VertexAttrib3fv(CONST_STRING_BINORMAL_ATTRIB, VertexMatrix[k_up].binorm.v);
|
||||
VertexAttrib3fv(CONST_STRING_TEXCOORD_ATTRIB, &std::array<float, 2>{ tx0, ty1 }[0]);
|
||||
glVertex3fv(VertexMatrix[k_up].pos.v);
|
||||
glEnd();
|
||||
|
||||
glBegin(GL_TRIANGLES);
|
||||
glNormal3fv(VertexMatrix[k_right_up].norm.v);
|
||||
VertexAttrib3fv(CONST_STRING_TANGENT_ATTRIB, VertexMatrix[k_right_up].tangent.v);
|
||||
VertexAttrib3fv(CONST_STRING_BINORMAL_ATTRIB, VertexMatrix[k_right_up].binorm.v);
|
||||
VertexAttrib3fv(CONST_STRING_TEXCOORD_ATTRIB, &std::array<float, 2>{ tx1, ty1 }[0]);
|
||||
glVertex3fv(VertexMatrix[k_right_up].pos.v);
|
||||
|
||||
glNormal3fv(VertexMatrix[k_up].norm.v);
|
||||
VertexAttrib3fv(CONST_STRING_TANGENT_ATTRIB, VertexMatrix[k_up].tangent.v);
|
||||
VertexAttrib3fv(CONST_STRING_BINORMAL_ATTRIB, VertexMatrix[k_up].binorm.v);
|
||||
VertexAttrib3fv(CONST_STRING_TEXCOORD_ATTRIB, &std::array<float, 2>{ tx0, ty1 }[0]);
|
||||
glVertex3fv(VertexMatrix[k_up].pos.v);
|
||||
|
||||
glNormal3fv(VertexMatrix[k_right].norm.v);
|
||||
VertexAttrib3fv(CONST_STRING_TANGENT_ATTRIB, VertexMatrix[k_right].tangent.v);
|
||||
VertexAttrib3fv(CONST_STRING_BINORMAL_ATTRIB, VertexMatrix[k_right].binorm.v);
|
||||
VertexAttrib3fv(CONST_STRING_TEXCOORD_ATTRIB, &std::array<float, 2>{ tx1, ty0 }[0]);
|
||||
glVertex3fv(VertexMatrix[k_right].pos.v);
|
||||
glEnd();*/
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
vertexDataStruct.RefreshVBO();
|
||||
|
||||
|
||||
/*IndexArr.resize(6 * (Width - 1) * (Height - 1));
|
||||
|
||||
//VBOLandVertexArr.resize(Width*Height);
|
||||
VBOLandVertexArr.pos.resize(Width * Height);
|
||||
VBOLandVertexArr.norm.resize(Width * Height);
|
||||
VBOLandVertexArr.tangent.resize(Width * Height);
|
||||
VBOLandVertexArr.binorm.resize(Width * Height);
|
||||
VBOLandVertexArr.texCoord.resize(Width * Height);
|
||||
VBOLandVertexArr.texCoord.resize(Width * Height);*/
|
||||
|
||||
|
||||
/*
|
||||
for (int i = 0; i < Height-1; i++)
|
||||
for (int j = 0; j < Width-1; j++)
|
||||
{
|
||||
@ -127,11 +215,15 @@ void TSimpleLandClass::CreateVBO()
|
||||
glBindBuffer(GL_ARRAY_BUFFER, TexcoordBuffer);
|
||||
glBufferData(GL_ARRAY_BUFFER, Width * Height * sizeof(vec2), &(VBOLandVertexArr.texCoord[0]), GL_STATIC_DRAW);
|
||||
#endif
|
||||
*/
|
||||
|
||||
|
||||
}
|
||||
|
||||
void TSimpleLandClass::FreeVBO()
|
||||
{
|
||||
|
||||
/*
|
||||
#ifdef TARGET_WIN32
|
||||
|
||||
glDeleteBuffers(1, &VertexBuffer);
|
||||
@ -147,13 +239,16 @@ void TSimpleLandClass::FreeVBO()
|
||||
VBOLandVertexArr.tangent.clear();
|
||||
VBOLandVertexArr.binorm.clear();
|
||||
VBOLandVertexArr.texCoord.clear();
|
||||
IndexArr.clear();
|
||||
IndexArr.clear();*/
|
||||
}
|
||||
|
||||
void TSimpleLandClass::UpdateVBO()
|
||||
{
|
||||
//Index array remains the same - only vertex array is to be changed
|
||||
CreateVBO();
|
||||
vertexDataStruct.RefreshVBO();
|
||||
|
||||
//Index array remains the same - only vertex array is to be changed
|
||||
/*
|
||||
for (int i = 0; i < Height; i++)
|
||||
{
|
||||
for (int j = 0; j < Width; j++)
|
||||
@ -184,6 +279,7 @@ void TSimpleLandClass::UpdateVBO()
|
||||
glBindBuffer(GL_ARRAY_BUFFER, TexcoordBuffer);
|
||||
glBufferSubData(GL_ARRAY_BUFFER, 0, Width * Height * sizeof(vec2), &(VBOLandVertexArr.texCoord[0]));
|
||||
#endif
|
||||
*/
|
||||
}
|
||||
|
||||
vec3 TSimpleLandClass::CalcCrossingForPoint(const vec3& pos, int i, int j)
|
||||
@ -441,21 +537,34 @@ void TSimpleLandClass::DrawVBO()
|
||||
{
|
||||
|
||||
|
||||
//RenderUniform1i(CONST_STRING_NORMALMAPEXISTS_UNIFORM, min<cardinal>(NormTexID, 1));
|
||||
|
||||
//RenderUniformMatrix3fv(CONST_STRING_MODELROTATEMATRIX_UNIFORM, false, (float*)IdentityMatrix.m);
|
||||
//RenderUniform3fv(CONST_STRING_MODELTRANSLATEVECTOR_UNIFORM, (float*)ZeroVec3.v);
|
||||
|
||||
if (NormTexID != 0)
|
||||
if (NormTexID == 0)
|
||||
{
|
||||
glActiveTexture(GL_TEXTURE1);
|
||||
glBindTexture(GL_TEXTURE_2D,NormTexID);
|
||||
RenderUniform1i(CONST_STRING_NORMALMAPEXISTS_UNIFORM, 0);
|
||||
}
|
||||
|
||||
glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, WhiteColor);
|
||||
|
||||
RenderUniformMatrix3fv(CONST_STRING_MODELROTATEMATRIX_UNIFORM, false, (float*)IdentityMatrix.m);
|
||||
RenderUniform3fv(CONST_STRING_MODELTRANSLATEVECTOR_UNIFORM, (float*)ZeroVec3.v);
|
||||
|
||||
glActiveTexture(GL_TEXTURE1);
|
||||
glBindTexture(GL_TEXTURE_2D, NormTexID);
|
||||
|
||||
glActiveTexture(GL_TEXTURE0);
|
||||
glBindTexture(GL_TEXTURE_2D,TexID);
|
||||
glBindTexture(GL_TEXTURE_2D, TexID);
|
||||
|
||||
EnableVertexAttribArray("vPosition");
|
||||
EnableVertexAttribArray("vTexCoord");
|
||||
|
||||
//Renderer->DrawTriangleList(TriangleList);
|
||||
DrawVertexDataStruct(vertexDataStruct);
|
||||
|
||||
DisableVertexAttribArray("vPosition");
|
||||
DisableVertexAttribArray("vTexCoord");
|
||||
|
||||
|
||||
/*
|
||||
#ifdef TARGET_WIN32
|
||||
|
||||
|
||||
@ -495,7 +604,7 @@ void TSimpleLandClass::DrawVBO()
|
||||
|
||||
glDrawElements(GL_TRIANGLES, 6*(Width-1)*(Height-1), GL_UNSIGNED_SHORT, &IndexArr[0]);
|
||||
|
||||
#endif
|
||||
#endif*/
|
||||
|
||||
RenderUniform1i(CONST_STRING_NORMALMAPEXISTS_UNIFORM,1);
|
||||
|
||||
|
@ -570,7 +570,7 @@ cardinal TTextureListClass::AddTextureFromUserdata(const std::string& fileName,
|
||||
}
|
||||
|
||||
|
||||
cardinal TTextureListClass::AddCubemapTexture(std::string filename[6])
|
||||
cardinal TTextureListClass::AddCubemapTexture(std::array<std::string, 6> filename)
|
||||
{
|
||||
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user