#include "render/Renderer.h" #include namespace ZL { Matrix4f MakeOrthoMatrix(float width, float height, float zNear, float zFar) { float depthRange = zFar - zNear; if (depthRange <= 0) { throw std::runtime_error("zFar must be greater than zNear"); } Matrix4f r; r.data()[0] = 2.f / width; r.data()[1] = 0; r.data()[2] = 0; r.data()[3] = 0; r.data()[4] = 0; r.data()[5] = 2.f / height; r.data()[6] = 0; r.data()[7] = 0; r.data()[8] = 0; r.data()[9] = 0; r.data()[10] = -1 / depthRange; r.data()[11] = 0; r.data()[12] = -1; r.data()[13] = -1; r.data()[14] = zNear / depthRange; r.data()[15] = 1; return r; } Matrix4f MakeOrthoMatrix(float xmin, float xmax, float ymin, float ymax, float zNear, float zFar) { float width = xmax - xmin; float height = ymax - ymin; float depthRange = zFar - zNear; if (width <= 0 || height <= 0 || depthRange <= 0) { throw std::runtime_error("Invalid dimensions for orthogonal matrix"); } Matrix4f r; r.data()[0] = 2.f / width; r.data()[5] = 2.f / height; r.data()[10] = -1.f / depthRange; r.data()[1] = r.data()[2] = r.data()[3] = 0; r.data()[4] = r.data()[6] = r.data()[7] = 0; r.data()[8] = r.data()[9] = r.data()[11] = 0; r.data()[12] = -(xmax + xmin) / width; r.data()[13] = -(ymax + ymin) / height; r.data()[14] = zNear / depthRange; r.data()[15] = 1.f; return r; } Matrix4f MakePerspectiveMatrix(float fovY, float aspectRatio, float zNear, float zFar) { float tanHalfFovy = tan(fovY / 2.f); Matrix4f r; if (zNear >= zFar || aspectRatio == 0) { throw std::runtime_error("Invalid perspective parameters"); } r.data()[0] = 1.f / (aspectRatio * tanHalfFovy); r.data()[1] = 0; r.data()[2] = 0; r.data()[3] = 0; r.data()[4] = 0; r.data()[5] = 1.f / (tanHalfFovy); r.data()[6] = 0; r.data()[7] = 0; r.data()[8] = 0; r.data()[9] = 0; r.data()[10] = -(zFar + zNear) / (zFar - zNear); r.data()[11] = -1; r.data()[12] = 0; r.data()[13] = 0; r.data()[14] = -(2.f * zFar * zNear) / (zFar - zNear); r.data()[15] = 0; return r; } VBOHolder::VBOHolder() { glGenBuffers(1, &Buffer); } VBOHolder::~VBOHolder() { glDeleteBuffers(1, &Buffer); } GLuint VBOHolder::getBuffer() { return Buffer; } VAOHolder::VAOHolder() { #ifndef EMSCRIPTEN #ifndef ANDROID glGenVertexArrays(1, &vao); #endif #endif } VAOHolder::~VAOHolder() { #ifndef EMSCRIPTEN #ifndef ANDROID #ifdef __linux__ glDeleteVertexArrays(1, &vao); #else //Windows glDeleteVertexArray(1, &vao); #endif #endif #endif } GLuint VAOHolder::getBuffer() { return vao; } VertexDataStruct CreateRect2D(Vector2f center, Vector2f halfWidthHeight, float zLevel) { Vector2f posFrom = center - halfWidthHeight; Vector2f posTo = center + halfWidthHeight; Vector3f pos1 = { posFrom(0), posFrom(1), zLevel }; Vector3f pos2 = { posFrom(0), posTo(1), zLevel }; Vector3f pos3 = { posTo(0), posTo(1), zLevel }; Vector3f pos4 = { posTo(0), posFrom(1), zLevel }; Vector2f texCoordPos1 = { 0.0f, 0.0f }; Vector2f texCoordPos2 = { 0.0f, 1.0f }; Vector2f texCoordPos3 = { 1.0f, 1.0f }; Vector2f texCoordPos4 = { 1.0f, 0.0f }; VertexDataStruct result; result.PositionData.push_back(pos1); result.PositionData.push_back(pos2); result.PositionData.push_back(pos3); result.PositionData.push_back(pos3); result.PositionData.push_back(pos4); result.PositionData.push_back(pos1); result.TexCoordData.push_back(texCoordPos1); result.TexCoordData.push_back(texCoordPos2); result.TexCoordData.push_back(texCoordPos3); result.TexCoordData.push_back(texCoordPos3); result.TexCoordData.push_back(texCoordPos4); result.TexCoordData.push_back(texCoordPos1); return result; } VertexDataStruct CreateRectHorizontalSections2D(Vector2f center, Vector2f halfWidthHeight, float zLevel, size_t sectionCount) { Vector2f posFrom = center - halfWidthHeight; Vector2f posTo = center + halfWidthHeight; float sectionWidth = halfWidthHeight(0) * 2.f; VertexDataStruct result; for (size_t i = 0; i < sectionCount; i++) { Vector3f pos1 = { posFrom(0)+sectionWidth*i, posFrom(1), zLevel }; Vector3f pos2 = { posFrom(0) + sectionWidth * i, posTo(1), zLevel }; Vector3f pos3 = { posTo(0) + sectionWidth * i, posTo(1), zLevel }; Vector3f pos4 = { posTo(0) + sectionWidth * i, posFrom(1), zLevel }; result.PositionData.push_back(pos1); result.PositionData.push_back(pos2); result.PositionData.push_back(pos3); result.PositionData.push_back(pos3); result.PositionData.push_back(pos4); result.PositionData.push_back(pos1); Vector2f texCoordPos1 = { 0.0f, 0.0f }; Vector2f texCoordPos2 = { 0.0f, 1.0f }; Vector2f texCoordPos3 = { 1.0f, 1.0f }; Vector2f texCoordPos4 = { 1.0f, 0.0f }; result.TexCoordData.push_back(texCoordPos1); result.TexCoordData.push_back(texCoordPos2); result.TexCoordData.push_back(texCoordPos3); result.TexCoordData.push_back(texCoordPos3); result.TexCoordData.push_back(texCoordPos4); result.TexCoordData.push_back(texCoordPos1); } return result; } VertexDataStruct CreateCube3D(float scale) { std::array, 6> cubeSides; std::array cubeColors; cubeSides[0][0] = { -1, -1, -1 }; cubeSides[0][1] = { -1, 1, -1 }; cubeSides[0][2] = { 1, 1, -1 }; cubeSides[0][3] = { 1, -1, -1 }; cubeSides[1][0] = { -1, -1, 1 }; cubeSides[1][1] = { -1, 1, 1 }; cubeSides[1][2] = { 1, 1, 1 }; cubeSides[1][3] = { 1, -1, 1 }; //------------ cubeSides[2][0] = { -1, -1, -1 }; cubeSides[2][1] = { -1, -1, 1 }; cubeSides[2][2] = { 1, -1, 1 }; cubeSides[2][3] = { 1, -1, -1 }; cubeSides[3][0] = { -1, 1, -1 }; cubeSides[3][1] = { -1, 1, 1 }; cubeSides[3][2] = { 1, 1, 1 }; cubeSides[3][3] = { 1, 1, -1 }; //------------ cubeSides[4][0] = { -1, -1, -1 }; cubeSides[4][1] = { -1, -1, 1 }; cubeSides[4][2] = { -1, 1, 1 }; cubeSides[4][3] = { -1, 1, -1 }; cubeSides[5][0] = { 1, -1, -1 }; cubeSides[5][1] = { 1, -1, 1 }; cubeSides[5][2] = { 1, 1, 1 }; cubeSides[5][3] = { 1, 1, -1 }; //----------- cubeColors[0] = Vector3f{ 1, 0, 0 }; cubeColors[1] = Vector3f{ 0, 1, 0 }; cubeColors[2] = Vector3f{ 0, 0, 1 }; cubeColors[3] = Vector3f{ 1, 1, 0 }; cubeColors[4] = Vector3f{ 0, 1, 1 }; cubeColors[5] = Vector3f{ 1, 0, 1 }; //----------- VertexDataStruct result; for (int i = 0; i < 6; i++) { result.PositionData.push_back(cubeSides[i][0] * scale); result.PositionData.push_back(cubeSides[i][1] * scale); result.PositionData.push_back(cubeSides[i][2] * scale); result.PositionData.push_back(cubeSides[i][2] * scale); result.PositionData.push_back(cubeSides[i][3] * scale); result.PositionData.push_back(cubeSides[i][0] * scale); result.ColorData.push_back(cubeColors[i]); result.ColorData.push_back(cubeColors[i]); result.ColorData.push_back(cubeColors[i]); result.ColorData.push_back(cubeColors[i]); result.ColorData.push_back(cubeColors[i]); result.ColorData.push_back(cubeColors[i]); } return result; } VertexDataStruct CreateCubemap(float scale) { VertexDataStruct cubemapVertexDataStruct; // +x cubemapVertexDataStruct.PositionData.push_back({ scale, -scale, -scale }); cubemapVertexDataStruct.PositionData.push_back({ scale, scale, -scale }); cubemapVertexDataStruct.PositionData.push_back({ scale, scale, scale }); cubemapVertexDataStruct.PositionData.push_back({ scale, -scale, -scale }); cubemapVertexDataStruct.PositionData.push_back({ scale, scale, scale }); cubemapVertexDataStruct.PositionData.push_back({ scale, -scale, scale }); // -x cubemapVertexDataStruct.PositionData.push_back({ -scale, -scale, -scale }); cubemapVertexDataStruct.PositionData.push_back({ -scale, scale, -scale }); cubemapVertexDataStruct.PositionData.push_back({ -scale, scale, scale }); cubemapVertexDataStruct.PositionData.push_back({ -scale, -scale, -scale }); cubemapVertexDataStruct.PositionData.push_back({ -scale, scale, scale }); cubemapVertexDataStruct.PositionData.push_back({ -scale, -scale, scale }); // +y cubemapVertexDataStruct.PositionData.push_back({ -scale, scale, -scale }); cubemapVertexDataStruct.PositionData.push_back({ scale, scale, -scale }); cubemapVertexDataStruct.PositionData.push_back({ scale, scale, scale }); cubemapVertexDataStruct.PositionData.push_back({ -scale, scale, -scale }); cubemapVertexDataStruct.PositionData.push_back({ scale, scale, scale }); cubemapVertexDataStruct.PositionData.push_back({ -scale, scale, scale }); // -y cubemapVertexDataStruct.PositionData.push_back({ -scale, -scale, -scale }); cubemapVertexDataStruct.PositionData.push_back({ scale, -scale, -scale }); cubemapVertexDataStruct.PositionData.push_back({ scale, -scale, scale }); cubemapVertexDataStruct.PositionData.push_back({ -scale, -scale, -scale }); cubemapVertexDataStruct.PositionData.push_back({ scale, -scale, scale }); cubemapVertexDataStruct.PositionData.push_back({ -scale, -scale, scale }); // +z cubemapVertexDataStruct.PositionData.push_back({ -scale, -scale, scale }); cubemapVertexDataStruct.PositionData.push_back({ scale, -scale, scale }); cubemapVertexDataStruct.PositionData.push_back({ scale, scale, scale }); cubemapVertexDataStruct.PositionData.push_back({ -scale, -scale, scale }); cubemapVertexDataStruct.PositionData.push_back({ scale, scale, scale }); cubemapVertexDataStruct.PositionData.push_back({ -scale, scale, scale }); // -z cubemapVertexDataStruct.PositionData.push_back({ -scale, -scale, -scale }); cubemapVertexDataStruct.PositionData.push_back({ scale, -scale, -scale }); cubemapVertexDataStruct.PositionData.push_back({ scale, scale, -scale }); cubemapVertexDataStruct.PositionData.push_back({ -scale, -scale, -scale }); cubemapVertexDataStruct.PositionData.push_back({ scale, scale, -scale }); cubemapVertexDataStruct.PositionData.push_back({ -scale, scale, -scale }); return cubemapVertexDataStruct; } void VertexRenderStruct::RefreshVBO() { //Check if main thread, check if data is not empty... #ifndef EMSCRIPTEN #ifndef __ANDROID__ if (!vao) { vao = std::make_shared(); } glBindVertexArray(vao->getBuffer()); #endif #endif if (!positionVBO) { positionVBO = std::make_shared(); } glBindBuffer(GL_ARRAY_BUFFER, positionVBO->getBuffer()); glBufferData(GL_ARRAY_BUFFER, data.PositionData.size() * 12, &data.PositionData[0], GL_STATIC_DRAW); if (data.TexCoordData.size() > 0) { if (!texCoordVBO) { texCoordVBO = std::make_shared(); } glBindBuffer(GL_ARRAY_BUFFER, texCoordVBO->getBuffer()); glBufferData(GL_ARRAY_BUFFER, data.TexCoordData.size() * 8, &data.TexCoordData[0], GL_STATIC_DRAW); } if (data.NormalData.size() > 0) { if (!normalVBO) { normalVBO = std::make_shared(); } glBindBuffer(GL_ARRAY_BUFFER, normalVBO->getBuffer()); glBufferData(GL_ARRAY_BUFFER, data.NormalData.size() * 12, &data.NormalData[0], GL_STATIC_DRAW); } if (data.TangentData.size() > 0) { if (!tangentVBO) { tangentVBO = std::make_shared(); } glBindBuffer(GL_ARRAY_BUFFER, tangentVBO->getBuffer()); glBufferData(GL_ARRAY_BUFFER, data.TangentData.size() * 12, &data.TangentData[0], GL_STATIC_DRAW); } if (data.BinormalData.size() > 0) { if (!binormalVBO) { binormalVBO = std::make_shared(); } glBindBuffer(GL_ARRAY_BUFFER, binormalVBO->getBuffer()); glBufferData(GL_ARRAY_BUFFER, data.BinormalData.size() * 12, &data.BinormalData[0], GL_STATIC_DRAW); } if (data.ColorData.size() > 0) { if (!colorVBO) { colorVBO = std::make_shared(); } glBindBuffer(GL_ARRAY_BUFFER, colorVBO->getBuffer()); glBufferData(GL_ARRAY_BUFFER, data.ColorData.size() * 12, &data.ColorData[0], GL_STATIC_DRAW); } } void VertexDataStruct::Scale(float scale) { for (int i = 0; i < PositionData.size(); i++) { PositionData[i] = PositionData[i] * scale; } } void VertexDataStruct::Move(Vector3f diff) { for (int i = 0; i < PositionData.size(); i++) { PositionData[i] = PositionData[i] + diff; } } void VertexDataStruct::SwapZandY() { for (int i = 0; i < PositionData.size(); i++) { auto value = PositionData[i](1); PositionData[i](1) = PositionData[i](2); PositionData[i](2) = value; } } void VertexDataStruct::RotateByMatrix(Matrix3f m) { for (int i = 0; i < PositionData.size(); i++) { PositionData[i] = PositionData[i].transpose() * m; } for (int i = 0; i < NormalData.size(); i++) { NormalData[i] = NormalData[i].transpose() * m; } for (int i = 0; i < TangentData.size(); i++) { TangentData[i] = TangentData[i].transpose() * m; } for (int i = 0; i < BinormalData.size(); i++) { BinormalData[i] = BinormalData[i].transpose() * m; } } void VertexRenderStruct::AssignFrom(const VertexDataStruct& v) { data = v; RefreshVBO(); } void Renderer::InitOpenGL() { ModelviewMatrixStack.push(Matrix4f::Identity()); ProjectionMatrixStack.push(Matrix4f::Identity()); glEnable(GL_DEPTH_TEST); glEnable(GL_BLEND); glActiveTexture(GL_TEXTURE0); #ifndef EMSCRIPTEN #ifndef __ANDROID__ glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); #endif #endif glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glDepthFunc(GL_LEQUAL); CheckGlError(); } void Renderer::PushProjectionMatrix(float width, float height, float zNear, float zFar) { Matrix4f m = MakeOrthoMatrix(width, height, zNear, zFar); ProjectionMatrixStack.push(m); SetMatrix(); if (ProjectionMatrixStack.size() > CONST_MATRIX_STACK_SIZE) { throw std::runtime_error("Projection matrix stack overflow!!!!"); } } void Renderer::PushProjectionMatrix(float xmin, float xmax, float ymin, float ymax, float zNear, float zFar) { Matrix4f m = MakeOrthoMatrix(xmin, xmax, ymin, ymax, zNear, zFar); ProjectionMatrixStack.push(m); SetMatrix(); if (ProjectionMatrixStack.size() > CONST_MATRIX_STACK_SIZE) { throw std::runtime_error("Projection matrix stack overflow!!!!"); } } void Renderer::PushPerspectiveProjectionMatrix(float fovY, float aspectRatio, float zNear, float zFar) { Matrix4f m = MakePerspectiveMatrix(fovY, aspectRatio, zNear, zFar); ProjectionMatrixStack.push(m); SetMatrix(); if (ProjectionMatrixStack.size() > CONST_MATRIX_STACK_SIZE) { throw std::runtime_error("Projection matrix stack overflow!!!!"); } } void Renderer::PopProjectionMatrix() { if (ProjectionMatrixStack.size() == 0) { throw std::runtime_error("Projection matrix stack underflow!!!!"); } ProjectionMatrixStack.pop(); SetMatrix(); } Matrix4f Renderer::GetProjectionModelViewMatrix() { return ProjectionModelViewMatrix; } Matrix4f Renderer::GetCurrentModelViewMatrix() { return ModelviewMatrixStack.top(); } void Renderer::SetMatrix() { if (ProjectionMatrixStack.size() <= 0) { throw std::runtime_error("Projection matrix stack out!"); } if (ModelviewMatrixStack.size() <= 0) { throw std::runtime_error("Modelview matrix stack out!"); } Matrix4f& modelViewMatrix = ModelviewMatrixStack.top(); ProjectionModelViewMatrix = ProjectionMatrixStack.top() * modelViewMatrix; static const std::string ProjectionModelViewMatrixName = "ProjectionModelViewMatrix"; RenderUniformMatrix4fv(ProjectionModelViewMatrixName, false, ProjectionModelViewMatrix.data()); static const std::string ModelViewMatrixName = "ModelViewMatrix"; RenderUniformMatrix4fv(ModelViewMatrixName, false, modelViewMatrix.data()); } void Renderer::PushMatrix() { if (ModelviewMatrixStack.size() == 0) { throw std::runtime_error("Modelview matrix stack underflow!!!!"); } ModelviewMatrixStack.push(ModelviewMatrixStack.top()); if (ModelviewMatrixStack.size() > CONST_MATRIX_STACK_SIZE) { throw std::runtime_error("Modelview matrix stack overflow!!!!"); } } void Renderer::LoadIdentity() { if (ModelviewMatrixStack.size() == 0) { throw std::runtime_error("Modelview matrix stack underflow!!!!"); } ModelviewMatrixStack.pop(); ModelviewMatrixStack.push(Matrix4f::Identity()); SetMatrix(); } void Renderer::TranslateMatrix(const Vector3f& p) { Matrix4f m = Matrix4f::Identity(); m.data()[12] = p(0); m.data()[13] = p(1); m.data()[14] = p(2); m = ModelviewMatrixStack.top() * m; if (ModelviewMatrixStack.size() == 0) { throw std::runtime_error("Modelview matrix stack underflow!!!!"); } ModelviewMatrixStack.pop(); ModelviewMatrixStack.push(m); SetMatrix(); } void Renderer::ScaleMatrix(float scale) { Matrix4f m = Matrix4f::Identity(); m.data()[0] = scale; m.data()[5] = scale; m.data()[10] = scale; m = ModelviewMatrixStack.top() * m; if (ModelviewMatrixStack.size() == 0) { throw std::runtime_error("Modelview matrix stack underflow!!!!"); } ModelviewMatrixStack.pop(); ModelviewMatrixStack.push(m); SetMatrix(); } void Renderer::ScaleMatrix(const Vector3f& scale) { Matrix4f m = Matrix4f::Identity(); m.data()[0] = scale(0); m.data()[5] = scale(1); m.data()[10] = scale(2); m = ModelviewMatrixStack.top() * m; if (ModelviewMatrixStack.size() == 0) { throw std::runtime_error("Modelview matrix stack underflow!!!!"); } ModelviewMatrixStack.pop(); ModelviewMatrixStack.push(m); SetMatrix(); } void Renderer::RotateMatrix(const Eigen::Quaternionf& q) { Matrix3f m3 = q.toRotationMatrix(); Matrix4f m = Matrix4f::Identity(); m.block<3, 3>(0, 0) = m3; m = ModelviewMatrixStack.top() * m; if (ModelviewMatrixStack.size() == 0) { throw std::runtime_error("Modelview matrix stack underflow!!!!"); } ModelviewMatrixStack.pop(); ModelviewMatrixStack.push(m); SetMatrix(); } void Renderer::RotateMatrix(const Matrix3f& m3) { Matrix4f m = Matrix4f::Identity(); m.block<3, 3>(0, 0) = m3; m = ModelviewMatrixStack.top() * m; if (ModelviewMatrixStack.size() == 0) { throw std::runtime_error("Modelview matrix stack underflow!!!!"); } ModelviewMatrixStack.pop(); ModelviewMatrixStack.push(m); SetMatrix(); } void Renderer::PushSpecialMatrix(const Matrix4f& m) { if (ModelviewMatrixStack.size() > 64) { throw std::runtime_error("Modelview matrix stack overflow!!!!"); } ModelviewMatrixStack.push(m); SetMatrix(); } void Renderer::PopMatrix() { if (ModelviewMatrixStack.size() == 0) { throw std::runtime_error("Modelview matrix stack underflow!!!!"); } ModelviewMatrixStack.pop(); SetMatrix(); } void Renderer::RenderUniformMatrix3fv(const std::string& uniformName, bool transpose, const float* value) { auto shader = shaderManager.GetCurrentShader(); auto uniform = shader->uniformList.find(uniformName); if (uniform != shader->uniformList.end()) { glUniformMatrix3fv(uniform->second, 1, transpose, value); } } void Renderer::RenderUniformMatrix4fv(const std::string& uniformName, bool transpose, const float* value) { auto shader = shaderManager.GetCurrentShader(); auto uniform = shader->uniformList.find(uniformName); if (uniform != shader->uniformList.end()) { glUniformMatrix4fv(uniform->second, 1, transpose, value); } } void Renderer::RenderUniform3fv(const std::string& uniformName, const float* value) { auto shader = shaderManager.GetCurrentShader(); auto uniform = shader->uniformList.find(uniformName); if (uniform != shader->uniformList.end()) { glUniform3fv(uniform->second, 1, value); } } void Renderer::RenderUniform4fv(const std::string& uniformName, const float* value) { auto shader = shaderManager.GetCurrentShader(); auto uniform = shader->uniformList.find(uniformName); if (uniform != shader->uniformList.end()) { glUniform4fv(uniform->second, 1, value); } } void Renderer::RenderUniform1i(const std::string& uniformName, const int value) { auto shader = shaderManager.GetCurrentShader(); auto uniform = shader->uniformList.find(uniformName); if (uniform != shader->uniformList.end()) { glUniform1i(uniform->second, value); } } void Renderer::RenderUniform1f(const std::string& uniformName, float value) { auto shader = shaderManager.GetCurrentShader(); auto uniform = shader->uniformList.find(uniformName); if (uniform != shader->uniformList.end()) { glUniform1fv(uniform->second, 1, &value); } } void Renderer::VertexAttribPointer2fv(const std::string& attribName, int stride, const char* pointer) { auto shader = shaderManager.GetCurrentShader(); if (shader->attribList.find(attribName) != shader->attribList.end()) glVertexAttribPointer(shader->attribList[attribName], 2, GL_FLOAT, GL_FALSE, stride, pointer); } void Renderer::VertexAttribPointer3fv(const std::string& attribName, int stride, const char* pointer) { auto shader = shaderManager.GetCurrentShader(); if (shader->attribList.find(attribName) != shader->attribList.end()) glVertexAttribPointer(shader->attribList[attribName], 3, GL_FLOAT, GL_FALSE, stride, pointer); } void Renderer::DrawVertexRenderStruct(const VertexRenderStruct& VertexRenderStruct) { static const std::string vNormal("vNormal"); static const std::string vTangent("vTangent"); static const std::string vBinormal("vBinormal"); static const std::string vColor("vColor"); static const std::string vTexCoord("vTexCoord"); static const std::string vPosition("vPosition"); // On WebGL (and when not using VAO), vertex attribute arrays must be explicitly // enabled before drawing. Desktop with VAO can rely on stored state; WebGL cannot. if (VertexRenderStruct.data.NormalData.size() > 0) { glBindBuffer(GL_ARRAY_BUFFER, VertexRenderStruct.normalVBO->getBuffer()); VertexAttribPointer3fv(vNormal, 0, NULL); //EnableVertexAttribArray(vNormal); } else { //DisableVertexAttribArray(vNormal); } if (VertexRenderStruct.data.TangentData.size() > 0) { glBindBuffer(GL_ARRAY_BUFFER, VertexRenderStruct.tangentVBO->getBuffer()); VertexAttribPointer3fv(vTangent, 0, NULL); //EnableVertexAttribArray(vTangent); } else { //DisableVertexAttribArray(vTangent); } if (VertexRenderStruct.data.BinormalData.size() > 0) { glBindBuffer(GL_ARRAY_BUFFER, VertexRenderStruct.binormalVBO->getBuffer()); VertexAttribPointer3fv(vBinormal, 0, NULL); //EnableVertexAttribArray(vBinormal); } else { //DisableVertexAttribArray(vBinormal); } if (VertexRenderStruct.data.ColorData.size() > 0) { glBindBuffer(GL_ARRAY_BUFFER, VertexRenderStruct.colorVBO->getBuffer()); VertexAttribPointer3fv(vColor, 0, NULL); //EnableVertexAttribArray(vColor); } else { //DisableVertexAttribArray(vColor); } if (VertexRenderStruct.data.TexCoordData.size() > 0) { glBindBuffer(GL_ARRAY_BUFFER, VertexRenderStruct.texCoordVBO->getBuffer()); VertexAttribPointer2fv(vTexCoord, 0, NULL); //EnableVertexAttribArray(vTexCoord); } else { //DisableVertexAttribArray(vTexCoord); } glBindBuffer(GL_ARRAY_BUFFER, VertexRenderStruct.positionVBO->getBuffer()); VertexAttribPointer3fv(vPosition, 0, NULL); //EnableVertexAttribArray(vPosition); glDrawArrays(GL_TRIANGLES, 0, static_cast(VertexRenderStruct.data.PositionData.size())); } void worldToScreenCoordinates(Vector3f objectPos, Matrix4f projectionModelView, int screenWidth, int screenHeight, int& screenX, int& screenY) { Vector4f inx = { objectPos(0), objectPos(1), objectPos(2), 1.0f }; Vector4f clipCoords = projectionModelView * inx; float ndcX = clipCoords(0) / clipCoords(3); float ndcY = clipCoords(1) / clipCoords(3); screenX = (int)((ndcX + 1.0f) * 0.5f * screenWidth); screenY = (int)((1.0f + ndcY) * 0.5f * screenHeight); } }