diff --git a/drape/glconstants.cpp b/drape/glconstants.cpp index 201ed342dd..8072b7afb5 100644 --- a/drape/glconstants.cpp +++ b/drape/glconstants.cpp @@ -67,6 +67,7 @@ const glConst GLRGB = GL_RGB; const glConst GLAlpha = GL_ALPHA; const glConst GLLuminance = GL_LUMINANCE; const glConst GLAlphaLuminance = GL_LUMINANCE_ALPHA; +const glConst GLDepthComponent = GL_DEPTH_COMPONENT; const glConst GLRGBA8 = GL_RGBA8_OES; const glConst GLRGBA4 = GL_RGBA4_OES; @@ -150,5 +151,13 @@ const glConst GLAlways = GL_ALWAYS; const glConst GLActiveUniforms = GL_ACTIVE_UNIFORMS; const glConst GLLineStrip = GL_LINE_STRIP; +const glConst GLTriangles = GL_TRIANGLES; +const glConst GLTriangleStrip = GL_TRIANGLE_STRIP; + +const glConst GLColorAttachment = GL_COLOR_ATTACHMENT0; +const glConst GLDepthAttachment = GL_DEPTH_ATTACHMENT; +const glConst GlStencilAttachment = GL_STENCIL_ATTACHMENT; + +const glConst GlFramebufferComplete = GL_FRAMEBUFFER_COMPLETE; } // namespace GLConst diff --git a/drape/glconstants.hpp b/drape/glconstants.hpp index 3928a2d6f8..05a4db4a8d 100644 --- a/drape/glconstants.hpp +++ b/drape/glconstants.hpp @@ -44,6 +44,7 @@ extern const glConst GLRGB; extern const glConst GLAlpha; extern const glConst GLLuminance; extern const glConst GLAlphaLuminance; +extern const glConst GLDepthComponent; /// Texture layout size extern const glConst GLRGBA8; @@ -143,5 +144,15 @@ extern const glConst GLActiveUniforms; /// Draw primitives extern const glConst GLLineStrip; +extern const glConst GLTriangles; +extern const glConst GLTriangleStrip; + +/// Framebuffer attachment points +extern const glConst GLColorAttachment; +extern const glConst GLDepthAttachment; +extern const glConst GlStencilAttachment; + +/// Framebuffer status +extern const glConst GlFramebufferComplete; } // namespace GLConst diff --git a/drape/glfunctions.cpp b/drape/glfunctions.cpp index 0e76a454af..d39754936b 100644 --- a/drape/glfunctions.cpp +++ b/drape/glfunctions.cpp @@ -41,7 +41,6 @@ typedef void (DP_APIENTRY *TglClearFn)(GLbitfield mask); typedef void (DP_APIENTRY *TglViewportFn)(GLint x, GLint y, GLsizei w, GLsizei h); typedef void (DP_APIENTRY *TglFlushFn)(); -typedef void (DP_APIENTRY *TglBindFramebufferFn)(GLenum target, GLuint id); typedef void (DP_APIENTRY *TglActiveTextureFn)(GLenum texture); typedef void (DP_APIENTRY *TglBlendEquationFn)(GLenum mode); @@ -95,12 +94,17 @@ typedef void (DP_APIENTRY *TglUniform4fFn)(GLint location, GLfloat v1, GLfloat v typedef void (DP_APIENTRY *TglUniform1fvFn)(GLint location, GLsizei count, GLfloat const * value); typedef void (DP_APIENTRY *TglUniformMatrix4fvFn)(GLint location, GLsizei count, GLboolean transpose, GLfloat const * value); +typedef void (DP_APIENTRY *TglGenFramebuffersFn)(GLsizei n, GLuint * framebuffers); +typedef void (DP_APIENTRY *TglDeleteFramebuffersFn)(GLsizei n, GLuint const * framebuffers); +typedef void (DP_APIENTRY *TglBindFramebufferFn)(GLenum target, GLuint id); +typedef void (DP_APIENTRY *TglFramebufferTexture2DFn)(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level); +typedef GLenum(DP_APIENTRY *TglCheckFramebufferStatusFn)(GLenum target); + TglClearColorFn glClearColorFn = nullptr; TglClearFn glClearFn = nullptr; TglViewportFn glViewportFn = nullptr; TglFlushFn glFlushFn = nullptr; -TglBindFramebufferFn glBindFramebufferFn = nullptr; TglActiveTextureFn glActiveTextureFn = nullptr; TglBlendEquationFn glBlendEquationFn = nullptr; @@ -155,6 +159,13 @@ TglUniform4fFn glUniform4fFn = nullptr; TglUniform1fvFn glUniform1fvFn = nullptr; TglUniformMatrix4fvFn glUniformMatrix4fvFn = nullptr; +/// FBO +TglGenFramebuffersFn glGenFramebuffersFn = nullptr; +TglDeleteFramebuffersFn glDeleteFramebuffersFn = nullptr; +TglBindFramebufferFn glBindFramebufferFn = nullptr; +TglFramebufferTexture2DFn glFramebufferTexture2DFn = nullptr; +TglCheckFramebufferStatusFn glCheckFramebufferStatusFn = nullptr; + int const GLCompileStatus = GL_COMPILE_STATUS; int const GLLinkStatus = GL_LINK_STATUS; @@ -389,7 +400,6 @@ void GLFunctions::Init() glViewportFn = &::glViewport; glFlushFn = &::glFlush; - glBindFramebufferFn = LOAD_GL_FUNC(TglBindFramebufferFn, glBindFramebuffer); glActiveTextureFn = LOAD_GL_FUNC(TglActiveTextureFn, glActiveTexture); glBlendEquationFn = LOAD_GL_FUNC(TglBlendEquationFn, glBlendEquation); @@ -444,6 +454,13 @@ void GLFunctions::Init() glUniform1fvFn = LOAD_GL_FUNC(TglUniform1fvFn, glUniform1fv); glUniformMatrix4fvFn = LOAD_GL_FUNC(TglUniformMatrix4fvFn, glUniformMatrix4fv); + + /// FBO + glGenFramebuffersFn = LOAD_GL_FUNC(TglGenFramebuffersFn, glGenFramebuffers); + glDeleteFramebuffersFn = LOAD_GL_FUNC(TglDeleteFramebuffersFn, glDeleteFramebuffers); + glBindFramebufferFn = LOAD_GL_FUNC(TglBindFramebufferFn, glBindFramebuffer); + glFramebufferTexture2DFn = LOAD_GL_FUNC(TglFramebufferTexture2DFn, glFramebufferTexture2D); + glCheckFramebufferStatusFn = LOAD_GL_FUNC(TglCheckFramebufferStatusFn, glCheckFramebufferStatus); } void GLFunctions::AttachCache(thread::id const & threadId) @@ -587,12 +604,6 @@ void GLFunctions::glBlendFunc(glConst srcFactor, glConst dstFactor) GLCHECK(::glBlendFunc(srcFactor, dstFactor)); } -void GLFunctions::glBindFramebuffer(glConst target, uint32_t id) -{ - ASSERT(glBindFramebufferFn != nullptr, ()); - GLCHECK(glBindFramebufferFn(target, id)); -} - uint32_t GLFunctions::glGenVertexArray() { ASSERT(glGenVertexArraysFn != nullptr, ()); @@ -963,6 +974,38 @@ void GLFunctions::glDrawArrays(glConst mode, int32_t first, uint32_t count) GLCHECK(::glDrawArrays(mode, first, count)); } +void GLFunctions::glGenFramebuffer(uint32_t * fbo) +{ + ASSERT(glGenFramebuffersFn != nullptr, ()); + GLCHECK(glGenFramebuffersFn(1, fbo)); +} + +void GLFunctions::glDeleteFramebuffer(uint32_t * fbo) +{ + ASSERT(glDeleteFramebuffersFn != nullptr, ()); + GLCHECK(glDeleteFramebuffersFn(1, fbo)); +} + +void GLFunctions::glFramebufferTexture2D(glConst attachment, glConst texture) +{ + ASSERT(glFramebufferTexture2DFn != nullptr, ()); + GLCHECK(glFramebufferTexture2DFn(GL_FRAMEBUFFER, attachment, GL_TEXTURE_2D, texture, 0)); +} + +void GLFunctions::glBindFramebuffer(uint32_t fbo) +{ + ASSERT(glBindFramebufferFn != nullptr, ()); + GLCHECK(glBindFramebufferFn(GL_FRAMEBUFFER, fbo)); +} + +uint32_t GLFunctions::glCheckFramebufferStatus() +{ + ASSERT(glCheckFramebufferStatusFn != nullptr, ()); + uint32_t result = glCheckFramebufferStatusFn(GL_FRAMEBUFFER); + GLCHECKCALL(); + return result; +} + namespace { diff --git a/drape/glfunctions.hpp b/drape/glfunctions.hpp index 96396f8ff4..95c2232d81 100644 --- a/drape/glfunctions.hpp +++ b/drape/glfunctions.hpp @@ -47,8 +47,6 @@ public: static void glBlendEquation(glConst function); static void glBlendFunc(glConst srcFactor, glConst dstFactor); - static void glBindFramebuffer(glConst target, uint32_t id); - /// VAO support static uint32_t glGenVertexArray(); static void glBindVertexArray(uint32_t vao); @@ -133,6 +131,13 @@ public: // Draw support static void glDrawElements(uint32_t sizeOfIndex, uint32_t indexCount, uint32_t startIndex = 0); static void glDrawArrays(glConst mode, int32_t first, uint32_t count); + + // FBO support + static void glGenFramebuffer(uint32_t * fbo); + static void glDeleteFramebuffer(uint32_t * fbo); + static void glBindFramebuffer(uint32_t fbo); + static void glFramebufferTexture2D(glConst attachment, glConst texture); + static uint32_t glCheckFramebufferStatus(); }; void CheckGLError(my::SrcPoint const &src); diff --git a/drape/shaders/shader_index.txt b/drape/shaders/shader_index.txt index edeff4488f..427ece5d8b 100644 --- a/drape/shaders/shader_index.txt +++ b/drape/shaders/shader_index.txt @@ -15,3 +15,4 @@ BOOKMARK_PROGRAM user_mark.vsh texturing_fragment_shader.fsh ROUTE_PROGRAM route_vertex_shader.vsh route_fragment_shader.fsh ROUTE_ARROW_PROGRAM route_vertex_shader.vsh route_arrow_fragment_shader.fsh DEBUG_RECT_PROGRAM debug_rect_vertex_shader.vsh debug_rect_fragment_shader.fsh +TEXTURING_3D_PROGRAM texturing3d_vertex_shader.vsh texturing3d_fragment_shader.fsh diff --git a/drape/shaders/texturing3d_fragment_shader.fsh b/drape/shaders/texturing3d_fragment_shader.fsh new file mode 100644 index 0000000000..89b9629911 --- /dev/null +++ b/drape/shaders/texturing3d_fragment_shader.fsh @@ -0,0 +1,7 @@ +uniform sampler2D tex; +varying vec2 v_tcoord; + +void main() +{ + gl_FragColor = texture2D(tex, v_tcoord); +} diff --git a/drape/shaders/texturing3d_vertex_shader.vsh b/drape/shaders/texturing3d_vertex_shader.vsh new file mode 100644 index 0000000000..62fa0230c3 --- /dev/null +++ b/drape/shaders/texturing3d_vertex_shader.vsh @@ -0,0 +1,18 @@ +attribute vec2 a_pos; +attribute vec2 a_tcoord; + +uniform mat4 rotate; +uniform mat4 translate; +uniform mat4 projection; + +varying vec2 v_tcoord; + +void main() +{ + + v_tcoord = a_tcoord; + gl_Position.xy = a_pos; + gl_Position.zw = vec2(0.0, 1.0); + gl_Position = projection * translate * rotate * gl_Position; +} + diff --git a/drape_frontend/drape_engine.cpp b/drape_frontend/drape_engine.cpp index 3cc873cac0..2b0b5955b6 100644 --- a/drape_frontend/drape_engine.cpp +++ b/drape_frontend/drape_engine.cpp @@ -429,4 +429,18 @@ gui::TWidgetsSizeInfo const & DrapeEngine::GetWidgetSizes() return m_widgetSizes; } +void DrapeEngine::Enable3dMode(float angleFOV, float angleX, float deltaZ) +{ + m_threadCommutator->PostMessage(ThreadsCommutator::RenderThread, + make_unique_dp(angleFOV, angleX, deltaZ), + MessagePriority::Normal); +} + +void DrapeEngine::Disable3dMode() +{ + m_threadCommutator->PostMessage(ThreadsCommutator::RenderThread, + make_unique_dp(), + MessagePriority::Normal); +} + } // namespace df diff --git a/drape_frontend/drape_engine.hpp b/drape_frontend/drape_engine.hpp index c7b10e4e5b..57f82e617f 100644 --- a/drape_frontend/drape_engine.hpp +++ b/drape_frontend/drape_engine.hpp @@ -114,6 +114,9 @@ public: void SetWidgetLayout(gui::TWidgetsLayoutInfo && info); gui::TWidgetsSizeInfo const & GetWidgetSizes(); + void Enable3dMode(float angleFOV, float angleX, float deltaZ); + void Disable3dMode(); + private: void AddUserEvent(UserEvent const & e); void ModelViewChanged(ScreenBase const & screen); diff --git a/drape_frontend/drape_frontend.pro b/drape_frontend/drape_frontend.pro index e67ab21921..2b8aaf6d0e 100755 --- a/drape_frontend/drape_frontend.pro +++ b/drape_frontend/drape_frontend.pro @@ -38,6 +38,7 @@ SOURCES += \ circle_shape.cpp \ drape_engine.cpp \ engine_context.cpp \ + framebuffer.cpp \ frontend_renderer.cpp \ line_shape.cpp \ line_shape_helper.cpp \ @@ -55,6 +56,7 @@ SOURCES += \ read_mwm_task.cpp \ render_group.cpp \ render_node.cpp \ + renderer3d.cpp \ requested_tiles.cpp \ route_builder.cpp \ route_renderer.cpp \ @@ -116,6 +118,7 @@ HEADERS += \ circle_shape.hpp \ drape_engine.hpp \ engine_context.hpp \ + framebuffer.hpp \ frontend_renderer.hpp \ intrusive_vector.hpp \ line_shape.hpp \ @@ -137,6 +140,7 @@ HEADERS += \ read_mwm_task.hpp \ render_group.hpp \ render_node.hpp \ + renderer3d.hpp \ requested_tiles.hpp \ route_builder.hpp \ route_renderer.hpp \ diff --git a/drape_frontend/framebuffer.cpp b/drape_frontend/framebuffer.cpp new file mode 100644 index 0000000000..0939bb5ba6 --- /dev/null +++ b/drape_frontend/framebuffer.cpp @@ -0,0 +1,101 @@ +#include "framebuffer.hpp" + +#include "drape/glfunctions.hpp" + +#include "base/assert.hpp" +#include "base/logging.hpp" +#include "base/string_utils.hpp" + +#include "math.h" + +#include "assert.h" + +namespace df +{ + +Framebuffer::Framebuffer() + : m_colorTextureId(0) + , m_depthTextureId(0) + , m_fbo(0) +{ + +} + +Framebuffer::~Framebuffer() +{ + Destroy(); +} + +void Framebuffer::Destroy() +{ + if (m_colorTextureId) + { + GLFunctions::glDeleteTexture(m_depthTextureId); + m_colorTextureId = 0; + } + if (m_depthTextureId) + { + GLFunctions::glDeleteTexture(m_depthTextureId); + m_depthTextureId = 0; + } + if (m_fbo) + { + GLFunctions::glDeleteFramebuffer(&m_fbo); + m_fbo = 0; + } +} + +void Framebuffer::SetSize(uint32_t width, uint32_t height) +{ + assert(width > 0 && height > 0); + if (m_width == width && m_height == height) + return; + + m_width = width; + m_height = height; + + Destroy(); + + m_colorTextureId = GLFunctions::glGenTexture(); + GLFunctions::glBindTexture(m_colorTextureId); + GLFunctions::glTexImage2D(m_width, m_height, gl_const::GLRGBA, gl_const::GLUnsignedByteType, NULL); + GLFunctions::glTexParameter(gl_const::GLMagFilter, gl_const::GLLinear); + GLFunctions::glTexParameter(gl_const::GLMinFilter, gl_const::GLLinear); + + m_depthTextureId = GLFunctions::glGenTexture(); + GLFunctions::glBindTexture(m_depthTextureId); + GLFunctions::glTexImage2D(m_width, m_height, gl_const::GLDepthComponent, gl_const::GLUnsignedIntType, NULL); + + GLFunctions::glBindTexture(0); + + GLFunctions::glGenFramebuffer(&m_fbo); + GLFunctions::glBindFramebuffer(m_fbo); + + GLFunctions::glFramebufferTexture2D(gl_const::GLColorAttachment, m_colorTextureId); + GLFunctions::glFramebufferTexture2D(gl_const::GLDepthAttachment, m_depthTextureId); + GLFunctions::glFramebufferTexture2D(gl_const::GlStencilAttachment, 0); + + uint32_t status = GLFunctions::glCheckFramebufferStatus(); + if (status != gl_const::GlFramebufferComplete) + LOG(LWARNING, ("INCOMPLETE FRAMEBUFFER: ", strings::to_string(status))); + + //GLFunctions::glFlush(); + GLFunctions::glBindFramebuffer(0); +} + +void Framebuffer::Enable() +{ + GLFunctions::glBindFramebuffer(m_fbo); +} + +void Framebuffer::Disable() +{ + GLFunctions::glBindFramebuffer(0); +} + +uint32_t Framebuffer::GetTextureId() const +{ + return m_colorTextureId; +} + +} diff --git a/drape_frontend/framebuffer.hpp b/drape_frontend/framebuffer.hpp new file mode 100644 index 0000000000..d471230bed --- /dev/null +++ b/drape_frontend/framebuffer.hpp @@ -0,0 +1,32 @@ +#pragma once + +#include "stdint.h" + +namespace df +{ + +class Framebuffer +{ +public: + Framebuffer(); + ~Framebuffer(); + + void SetSize(uint32_t width, uint32_t height); + + void Enable(); + void Disable(); + + uint32_t GetTextureId() const; + +private: + void Destroy(); + + uint32_t m_width; + uint32_t m_height; + + uint32_t m_colorTextureId; + uint32_t m_depthTextureId; + uint32_t m_fbo; +}; + +} diff --git a/drape_frontend/frontend_renderer.cpp b/drape_frontend/frontend_renderer.cpp index 4cf8c43987..403a137f5b 100755 --- a/drape_frontend/frontend_renderer.cpp +++ b/drape_frontend/frontend_renderer.cpp @@ -4,6 +4,8 @@ #include "drape_frontend/message_subclasses.hpp" #include "drape_frontend/visual_params.hpp" #include "drape_frontend/user_mark_shapes.hpp" +#include "drape_frontend/framebuffer.hpp" +#include "drape_frontend/renderer3d.hpp" #include "drape/debug_rect_renderer.hpp" #include "drape/support_manager.hpp" @@ -42,6 +44,9 @@ FrontendRenderer::FrontendRenderer(Params const & params) , m_gpuProgramManager(new dp::GpuProgramManager()) , m_routeRenderer(new RouteRenderer()) , m_overlayTree(new dp::OverlayTree()) + , m_useFramebuffer(true) + , m_framebuffer(new Framebuffer()) + , m_renderer3d(new Renderer3d()) , m_viewport(params.m_viewport) , m_userEventStream(params.m_isCountryLoadedFn) , m_modelViewChangedFn(params.m_modelViewChangedFn) @@ -65,7 +70,6 @@ FrontendRenderer::FrontendRenderer(Params const & params) m_myPositionController.reset(new MyPositionController(params.m_initMyPositionMode)); m_myPositionController->SetModeListener(params.m_myPositionModeCallback); - StartThread(); } @@ -457,6 +461,21 @@ void FrontendRenderer::AcceptMessage(ref_ptr message) break; } + case Message::Enable3dMode: + { + ref_ptr msg = message; + m_renderer3d->SetVerticalFOV(msg->GetAngleFOV()); + m_renderer3d->SetPlaneAngleX(msg->GetAngleX()); + m_renderer3d->SetPlaneOffsetZ(msg->GetDeltaZ()); + m_useFramebuffer = true; + break; + } + + case Message::Disable3dMode: + { + m_useFramebuffer = false; + break; + } case Message::Invalidate: { @@ -479,6 +498,8 @@ void FrontendRenderer::OnResize(ScreenBase const & screen) m_viewport.SetViewport(0, 0, screen.GetWidth(), screen.GetHeight()); m_myPositionController->SetPixelRect(screen.PixelRect()); m_contextFactory->getDrawContext()->resize(m_viewport.GetWidth(), m_viewport.GetHeight()); + m_framebuffer->SetSize(m_viewport.GetWidth(), m_viewport.GetHeight()); + m_renderer3d->SetSize(m_viewport.GetWidth(), m_viewport.GetHeight()); RefreshProjection(); } @@ -632,6 +653,9 @@ void FrontendRenderer::RenderScene(ScreenBase const & modelView) BeforeDrawFrame(); #endif + if (m_useFramebuffer) + m_framebuffer->Enable(); + RenderGroupComparator comparator; sort(m_renderGroups.begin(), m_renderGroups.end(), bind(&RenderGroupComparator::operator (), &comparator, _1, _2)); @@ -731,6 +755,12 @@ void FrontendRenderer::RenderScene(ScreenBase const & modelView) if (m_guiRenderer != nullptr) m_guiRenderer->Render(make_ref(m_gpuProgramManager), modelView); + if (m_useFramebuffer) + { + m_framebuffer->Disable(); + m_renderer3d->Render(m_framebuffer->GetTextureId(), make_ref(m_gpuProgramManager)); + } + GLFunctions::glEnable(gl_const::GLDepthTest); #ifdef DRAW_INFO diff --git a/drape_frontend/frontend_renderer.hpp b/drape_frontend/frontend_renderer.hpp index c6f11180e6..de798137ca 100755 --- a/drape_frontend/frontend_renderer.hpp +++ b/drape_frontend/frontend_renderer.hpp @@ -46,6 +46,8 @@ namespace df { class SelectionShape; +class Framebuffer; +class Renderer3d; struct TapInfo { @@ -224,6 +226,10 @@ private: dp::UniformValuesStorage m_generalUniforms; + bool m_useFramebuffer; + drape_ptr m_framebuffer; + drape_ptr m_renderer3d; + Viewport m_viewport; UserEventStream m_userEventStream; TModelViewChanged m_modelViewChangedFn; diff --git a/drape_frontend/message.hpp b/drape_frontend/message.hpp index 534c5e2cb1..d050b7ddf9 100644 --- a/drape_frontend/message.hpp +++ b/drape_frontend/message.hpp @@ -42,7 +42,9 @@ public: DeactivateRouteFollowing, UpdateMapStyle, InvalidateTextures, - Invalidate + Invalidate, + Enable3dMode, + Disable3dMode }; virtual ~Message() {} diff --git a/drape_frontend/message_subclasses.hpp b/drape_frontend/message_subclasses.hpp index ab074ecb77..9f0fbc828d 100644 --- a/drape_frontend/message_subclasses.hpp +++ b/drape_frontend/message_subclasses.hpp @@ -630,4 +630,34 @@ public: Type GetType() const override { return Message::DeactivateRouteFollowing; } }; +class Enable3dModeMessage : public Message +{ +public: + Enable3dModeMessage(float angleFOV, float angleX, float deltaZ) + : m_angleFOV(angleFOV) + , m_angleX(angleX) + , m_deltaZ(deltaZ) + {} + + Type GetType() const override { return Message::Enable3dMode; } + + float GetAngleFOV() const { return m_angleFOV; } + float GetAngleX() const { return m_angleX; } + float GetDeltaZ() const { return m_deltaZ; } + +private: + float m_angleFOV; + float m_angleX; + float m_deltaZ; +}; + +class Disable3dModeMessage : public Message +{ +public: + Disable3dModeMessage() + {} + + Type GetType() const override { return Message::Disable3dMode; } +}; + } // namespace df diff --git a/drape_frontend/renderer3d.cpp b/drape_frontend/renderer3d.cpp new file mode 100644 index 0000000000..deb55babff --- /dev/null +++ b/drape_frontend/renderer3d.cpp @@ -0,0 +1,173 @@ +#include "renderer3d.hpp" + +#include "drape/data_buffer.hpp" +#include "drape/glconstants.hpp" +#include "drape/glfunctions.hpp" +#include "drape/glstate.hpp" +#include "drape/shader_def.hpp" +#include "drape/uniform_values_storage.hpp" + +#include "math.h" + +namespace df +{ + +Renderer3d::Renderer3d() + : m_width(0) + , m_height(0) + , m_fov(M_PI / 3.0f) + , m_angleX(-M_PI_4) + , m_offsetZ(0.5f) + , m_VAO(0) + , m_bufferId(0) +{ + UpdateProjectionMatrix(); + UpdateRotationMatrix(); + UpdateTranslationMatrix(); +} + +Renderer3d::~Renderer3d() +{ + if (m_bufferId) + GLFunctions::glDeleteBuffer(m_bufferId); + if (m_VAO) + GLFunctions::glDeleteVertexArray(m_VAO); +} + +void Renderer3d::SetSize(uint32_t width, uint32_t height) +{ + m_width = width; + m_height = height; + + UpdateProjectionMatrix(); +} + +void Renderer3d::SetVerticalFOV(float fov) +{ + m_fov = fov; + + UpdateProjectionMatrix(); +} + +void Renderer3d::SetPlaneAngleX(float angleX) +{ + m_angleX = angleX; + + UpdateRotationMatrix(); +} + +void Renderer3d::SetPlaneOffsetZ(float offsetZ) +{ + m_offsetZ = offsetZ; + + UpdateTranslationMatrix(); +} + +void Renderer3d::Build(ref_ptr prg) +{ + m_bufferId = GLFunctions::glGenBuffer(); + GLFunctions::glBindBuffer(m_bufferId, gl_const::GLArrayBuffer); + + m_VAO = GLFunctions::glGenVertexArray(); + GLFunctions::glBindVertexArray(m_VAO); + + int8_t attributeLocation = prg->GetAttributeLocation("a_pos"); + assert(attributeLocation != -1); + GLFunctions::glEnableVertexAttribute(attributeLocation); + GLFunctions::glVertexAttributePointer(attributeLocation, 2, gl_const::GLFloatType, false, + sizeof(float) * 4, 0); + + attributeLocation = prg->GetAttributeLocation("a_tcoord"); + assert(attributeLocation != -1); + GLFunctions::glEnableVertexAttribute(attributeLocation); + GLFunctions::glVertexAttributePointer(attributeLocation, 2, gl_const::GLFloatType, false, + sizeof(float) * 4, sizeof(float) * 2); + + const float vertices[] = + { + -1.0f, 1.0f, 0.0f, 1.0f, + 1.0f, 1.0f, 1.0f, 1.0f, + -1.0f, -1.0f, 0.0f, 0.0f, + 1.0f, -1.0f, 1.0f, 0.0f + }; + GLFunctions::glBufferData(gl_const::GLArrayBuffer, sizeof(vertices), vertices, gl_const::GLStaticDraw); +} + +void Renderer3d::Render(uint32_t textureId, ref_ptr mng) +{ + ref_ptr prg = mng->GetProgram(gpu::TEXTURING_3D_PROGRAM); + prg->Bind(); + + if (!m_VAO) + Build(prg); + + dp::UniformValuesStorage uniforms; + uniforms.SetIntValue("tex", 0); + uniforms.SetMatrix4x4Value("rotate", m_rotationMatrix.data()); + uniforms.SetMatrix4x4Value("translate", m_translationMatrix.data()); + uniforms.SetMatrix4x4Value("projection", m_projectionMatrix.data()); + + dp::ApplyUniforms(uniforms, prg); + + GLFunctions::glDisable(gl_const::GLDepthTest); + + GLFunctions::glActiveTexture(gl_const::GLTexture0); + GLFunctions::glBindTexture(textureId); + GLFunctions::glBindBuffer(m_bufferId, gl_const::GLArrayBuffer); + GLFunctions::glBindVertexArray(m_VAO); + + GLFunctions::glClear(); + GLFunctions::glDrawArrays(gl_const::GLTriangleStrip, 0, 4); + + prg->Unbind(); + GLFunctions::glBindTexture(0); + GLFunctions::glBindVertexArray(0); + GLFunctions::glBindBuffer(0, gl_const::GLArrayBuffer); +} + +void Renderer3d::UpdateProjectionMatrix() +{ + float ctg_fovy = 1.0/tanf(m_fov/2.0f); + float aspect = (float)m_width / m_height; + float near = 0.1f; + float far = 100.0f; + + m_projectionMatrix.fill(0.0f); + + m_projectionMatrix[0] = ctg_fovy / aspect; + m_projectionMatrix[5] = ctg_fovy; + m_projectionMatrix[10] = (far + near) / (far - near); + m_projectionMatrix[11] = 1.0f; + m_projectionMatrix[14] = -2 * far * near / (far - near); +} + +void Renderer3d::UpdateRotationMatrix() +{ + m_rotationMatrix.fill(0.0f); + + m_rotationMatrix[0] = 1.0f; + m_rotationMatrix[5] = cos(m_angleX); + m_rotationMatrix[6] = -sin(m_angleX); + m_rotationMatrix[9] = sin(m_angleX); + m_rotationMatrix[10] = cos(m_angleX); + m_rotationMatrix[15] = 1.0f; +} + +void Renderer3d::UpdateTranslationMatrix() +{ + m_translationMatrix.fill(0.0f); + + float dx = 0.0f; + float dy = 0.0f; + float dz = m_offsetZ; + + m_translationMatrix[0] = 1.0f; + m_translationMatrix[5] = 1.0f; + m_translationMatrix[10] = 1.0f; + m_translationMatrix[12] = dx; + m_translationMatrix[13] = dy; + m_translationMatrix[14] = dz; + m_translationMatrix[15] = 1.0f; +} + +} diff --git a/drape_frontend/renderer3d.hpp b/drape_frontend/renderer3d.hpp new file mode 100644 index 0000000000..0898fee245 --- /dev/null +++ b/drape_frontend/renderer3d.hpp @@ -0,0 +1,44 @@ +#pragma once + +#include "drape/gpu_program_manager.hpp" +#include "viewport.hpp" + +namespace df +{ + +class Renderer3d +{ +public: + Renderer3d(); + ~Renderer3d(); + + void SetSize(uint32_t width, uint32_t height); + void SetVerticalFOV(float fov); + void SetPlaneAngleX(float angleX); + void SetPlaneOffsetZ(float offsetZ); + + void Render(uint32_t textureId, ref_ptr mng); + +private: + void Build(ref_ptr prg); + + void UpdateRotationMatrix(); + void UpdateTranslationMatrix(); + void UpdateProjectionMatrix(); + + uint32_t m_width; + uint32_t m_height; + + float m_fov; + float m_angleX; + float m_offsetZ; + + array m_rotationMatrix; + array m_translationMatrix; + array m_projectionMatrix; + + uint32_t m_VAO; + uint32_t m_bufferId; +}; + +}