From ae02fe2c385b90e02537be29f2f036e47d1bdddf Mon Sep 17 00:00:00 2001 From: Hleb Valoshka <375gnu@gmail.com> Date: Fri, 8 Nov 2019 00:56:56 +0300 Subject: [PATCH] Refactor selection pointer to use glsl and common BO --- shaders/selpointer_frag.glsl | 8 +++ shaders/selpointer_vert.glsl | 14 +++++ src/celengine/glmarker.cpp | 108 ++++++++++++++++++++++++++++++++--- src/celengine/render.cpp | 83 --------------------------- 4 files changed, 121 insertions(+), 92 deletions(-) create mode 100644 shaders/selpointer_frag.glsl create mode 100644 shaders/selpointer_vert.glsl diff --git a/shaders/selpointer_frag.glsl b/shaders/selpointer_frag.glsl new file mode 100644 index 00000000..a8301b3c --- /dev/null +++ b/shaders/selpointer_frag.glsl @@ -0,0 +1,8 @@ +#version 120 + +uniform vec4 color; + +void main(void) +{ + gl_FragColor = color; +} diff --git a/shaders/selpointer_vert.glsl b/shaders/selpointer_vert.glsl new file mode 100644 index 00000000..8329729e --- /dev/null +++ b/shaders/selpointer_vert.glsl @@ -0,0 +1,14 @@ +#version 120 + +uniform float pixelSize; +uniform float s, c; +uniform float x0, y0; +uniform vec3 u, v; + +void main(void) +{ + float x = gl_Vertex.x * pixelSize; + float y = gl_Vertex.y * pixelSize; + vec3 pos = (x * c - y * s + x0) * u + (x * s + y * c + y0) * v; + gl_Position = gl_ModelViewProjectionMatrix * vec4(pos, 1.0f); +} diff --git a/src/celengine/glmarker.cpp b/src/celengine/glmarker.cpp index b497a021..c7a71219 100644 --- a/src/celengine/glmarker.cpp +++ b/src/celengine/glmarker.cpp @@ -10,6 +10,7 @@ #include "marker.h" #include +#include #include #include #include "render.h" @@ -130,9 +131,18 @@ static GLfloat DownArrow[DownArrowCount * 2] = 0.0f, 1.0f }; -constexpr const int StaticVtxCount = DownArrowOffset + DownArrowCount; +constexpr const int SelPointerOffset = DownArrowOffset + DownArrowCount; +constexpr const int SelPointerCount = 3; +static GLfloat SelPointer[SelPointerCount * 2] = +{ + 0.0f, 0.0f, + -20.0f, 6.0f, + -20.0f, -6.0f +}; -constexpr const int SmallCircleOffset = DownArrowOffset + DownArrowCount; +constexpr const int StaticVtxCount = SelPointerOffset + SelPointerCount; + +constexpr const int SmallCircleOffset = StaticVtxCount; static int SmallCircleCount = 0; static int LargeCircleOffset = 0; static int LargeCircleCount = 0; @@ -170,10 +180,11 @@ static void initVO(VertexObject& vo) VOSTREAM(LeftArrow); VOSTREAM(UpArrow); VOSTREAM(DownArrow); + VOSTREAM(SelPointer); #undef VOSTREAM - vo.setBufferData(small.data(), VTXTOMEM(SmallCircleOffset), small.size() * sizeof(GLfloat)); - vo.setBufferData(large.data(), VTXTOMEM(LargeCircleOffset), large.size() * sizeof(GLfloat)); + vo.setBufferData(small.data(), VTXTOMEM(SmallCircleOffset), memsize(small)); + vo.setBufferData(large.data(), VTXTOMEM(LargeCircleOffset), memsize(large)); #undef VTXTOMEM vo.setVertices(2, GL_FLOAT, false, 0, 0); @@ -181,16 +192,15 @@ static void initVO(VertexObject& vo) void Renderer::renderMarker(MarkerRepresentation::Symbol symbol, float size, const Color& color) { - markerVO.bind(); - - if (!markerVO.initialized()) - initVO(markerVO); - assert(shaderManager != nullptr); auto* prog = shaderManager->getShader("marker"); if (prog == nullptr) return; + markerVO.bind(); + if (!markerVO.initialized()) + initVO(markerVO); + float s = size / 2.0f; prog->use(); prog->vec4Param("color") = color.toVector4(); @@ -259,3 +269,83 @@ void Renderer::renderMarker(MarkerRepresentation::Symbol symbol, float size, con glUseProgram(0); markerVO.unbind(); } + +/*! Draw an arrow at the view border pointing to an offscreen selection. This method + * should only be called when the selection lies outside the view frustum. + */ +void Renderer::renderSelectionPointer(const Observer& observer, + double now, + const Frustum& viewFrustum, + const Selection& sel) +{ + constexpr const float cursorDistance = 20.0f; + if (sel.empty()) + return; + + // Get the position of the cursor relative to the eye + Vector3d position = sel.getPosition(now).offsetFromKm(observer.getPosition()); + if (viewFrustum.testSphere(position, sel.radius()) != Frustum::Outside) + return; + + assert(shaderManager != nullptr); + auto* prog = shaderManager->getShader("selpointer"); + if (prog == nullptr) + return; + + Matrix3f cameraMatrix = observer.getOrientationf().conjugate().toRotationMatrix(); + const Vector3f u = cameraMatrix.col(0); + const Vector3f v = cameraMatrix.col(1); + double distance = position.norm(); + position *= cursorDistance / distance; + +#ifdef USE_HDR + glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_FALSE); +#endif + glDisable(GL_DEPTH_TEST); + glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + + float vfov = (float) observer.getFOV(); + float h = tan(vfov / 2); + float w = h * getAspectRatio(); + float diag = sqrt(h * h + w * w); + + Vector3f posf = position.cast() / cursorDistance; + float x = u.dot(posf); + float y = v.dot(posf); + float c, s; + sincos(atan2(y, x), s, c); + + float x0 = c * diag; + float y0 = s * diag; + float t = (std::abs(x0) < w) ? h / abs(y0) : w / abs(x0); + x0 *= t; + y0 *= t; + + const Vector3f ¢er = cameraMatrix.col(2); + glPushMatrix(); + glTranslatef(-center.x(), -center.y(), -center.z()); + + markerVO.bind(); + if (!markerVO.initialized()) + initVO(markerVO); + prog->use(); + prog->vec4Param("color") = Color(SelectionCursorColor, 0.6f).toVector4(); + prog->floatParam("pixelSize") = pixelSize; + prog->floatParam("s") = s; + prog->floatParam("c") = c; + prog->floatParam("x0") = x0; + prog->floatParam("y0") = y0; + prog->vec3Param("u") = u; + prog->vec3Param("v") = v; + markerVO.draw(GL_TRIANGLES, SelPointerCount, SelPointerOffset); + + glUseProgram(0); + markerVO.unbind(); + + glPopMatrix(); + +#ifdef USE_HDR + glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); +#endif +} diff --git a/src/celengine/render.cpp b/src/celengine/render.cpp index fe3859d1..5b255279 100644 --- a/src/celengine/render.cpp +++ b/src/celengine/render.cpp @@ -7174,89 +7174,6 @@ void Renderer::renderSkyGrids(const Observer& observer) } } - -/*! Draw an arrow at the view border pointing to an offscreen selection. This method - * should only be called when the selection lies outside the view frustum. - */ -void Renderer::renderSelectionPointer(const Observer& observer, - double now, - const Frustum& viewFrustum, - const Selection& sel) -{ - const float cursorDistance = 20.0f; - if (sel.empty()) - return; - - Matrix3f cameraMatrix = observer.getOrientationf().conjugate().toRotationMatrix(); - Vector3f u = cameraMatrix * Vector3f::UnitX(); - Vector3f v = cameraMatrix * Vector3f::UnitY(); - - // Get the position of the cursor relative to the eye - Vector3d position = sel.getPosition(now).offsetFromKm(observer.getPosition()); - double distance = position.norm(); - bool isVisible = viewFrustum.testSphere(position, sel.radius()) != Frustum::Outside; - position *= cursorDistance / distance; - -#ifdef USE_HDR - glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_FALSE); -#endif - glDisable(GL_DEPTH_TEST); - glDisable(GL_TEXTURE_2D); - glEnable(GL_BLEND); - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - - if (!isVisible) - { - double viewAspectRatio = (double) windowWidth / (double) windowHeight; - double vfov = observer.getFOV(); - auto h = (float) tan(vfov / 2); - auto w = (float) (h * viewAspectRatio); - float diag = std::sqrt(h * h + w * w); - - Vector3f posf = position.cast(); - posf *= (1.0f / cursorDistance); - float x = u.dot(posf); - float y = v.dot(posf); - float angle = std::atan2(y, x); - float c = std::cos(angle); - float s = std::sin(angle); - - float t = 1.0f; - float x0 = c * diag; - float y0 = s * diag; - if (std::abs(x0) < w) - t = h / std::abs(y0); - else - t = w / std::abs(x0); - x0 *= t; - y0 *= t; - glColor(SelectionCursorColor, 0.6f); - Vector3f center = -cameraMatrix * Vector3f::UnitZ(); - - glPushMatrix(); - glTranslatef(center.x(), center.y(), center.z()); - - Vector3f p0(Vector3f::Zero()); - Vector3f p1(-20.0f * pixelSize, 6.0f * pixelSize, 0.0f); - Vector3f p2(-20.0f * pixelSize, -6.0f * pixelSize, 0.0f); - - glBegin(GL_TRIANGLES); - glVertex((p0.x() * c - p0.y() * s + x0) * u + (p0.x() * s + p0.y() * c + y0) * v); - glVertex((p1.x() * c - p1.y() * s + x0) * u + (p1.x() * s + p1.y() * c + y0) * v); - glVertex((p2.x() * c - p2.y() * s + x0) * u + (p2.x() * s + p2.y() * c + y0) * v); - glEnd(); - - glPopMatrix(); - } - -#ifdef USE_HDR - glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); -#endif - - glEnable(GL_TEXTURE_2D); -} - - void Renderer::labelConstellations(const AsterismList& asterisms, const Observer& observer) {