From 668fd219cc7d18ca3887ea0125a694edaea02747 Mon Sep 17 00:00:00 2001 From: Levin Li Date: Sat, 5 Dec 2020 17:56:43 +0800 Subject: [PATCH] Render lines with triangles --- shaders/ecliptic_frag.glsl | 6 - shaders/ecliptic_vert.glsl | 7 - src/celengine/asterismrenderer.cpp | 56 ++--- src/celengine/asterismrenderer.h | 3 +- src/celengine/axisarrow.cpp | 164 +++++++++---- src/celengine/boundariesrenderer.cpp | 45 ++-- src/celengine/boundariesrenderer.h | 3 +- src/celengine/curveplot.cpp | 80 +++--- src/celengine/glmarker.cpp | 348 +++++++++++++++++++-------- src/celengine/planetgrid.cpp | 55 +++-- src/celengine/planetgrid.h | 6 +- src/celengine/rendcontext.cpp | 14 +- src/celengine/render.cpp | 125 +++++++--- src/celengine/render.h | 32 ++- src/celengine/shadermanager.cpp | 86 ++++++- src/celengine/shadermanager.h | 7 + src/celengine/skygrid.cpp | 82 +++++-- src/celengine/visibleregion.cpp | 31 ++- 18 files changed, 808 insertions(+), 342 deletions(-) delete mode 100644 shaders/ecliptic_frag.glsl delete mode 100644 shaders/ecliptic_vert.glsl diff --git a/shaders/ecliptic_frag.glsl b/shaders/ecliptic_frag.glsl deleted file mode 100644 index b51cfff39..000000000 --- a/shaders/ecliptic_frag.glsl +++ /dev/null @@ -1,6 +0,0 @@ -uniform vec4 color; - -void main(void) -{ - gl_FragColor = color; -} diff --git a/shaders/ecliptic_vert.glsl b/shaders/ecliptic_vert.glsl deleted file mode 100644 index 4abc4eb41..000000000 --- a/shaders/ecliptic_vert.glsl +++ /dev/null @@ -1,7 +0,0 @@ -attribute vec2 in_Position; - -void main(void) -{ - vec4 p = vec4(in_Position.x, 0.0, in_Position.y, 1.0); - set_vp(p); -} diff --git a/src/celengine/asterismrenderer.cpp b/src/celengine/asterismrenderer.cpp index 6ca2c08bb..13cc0311a 100644 --- a/src/celengine/asterismrenderer.cpp +++ b/src/celengine/asterismrenderer.cpp @@ -17,7 +17,7 @@ using namespace std; AsterismRenderer::AsterismRenderer(const AsterismList *asterisms) : m_asterisms(asterisms) { - m_shadprop.texUsage = ShaderProperties::VertexColors; + m_shadprop.texUsage = ShaderProperties::VertexColors | ShaderProperties::LineAsTriangles; m_shadprop.lightModel = ShaderProperties::UnlitModel; } @@ -37,22 +37,25 @@ void AsterismRenderer::render(const Renderer &renderer, const Color &defaultColo m_vo.bind(); if (!m_vo.initialized()) { - auto *vtxBuf = prepare(); - if (vtxBuf == nullptr) + std::vector data; + if (!prepare(data)) { m_vo.unbind(); return; } - m_vo.allocate(m_vtxTotal * 3 * sizeof(GLfloat), vtxBuf); - m_vo.setVertices(3, GL_FLOAT, false, 0, 0); - delete[] vtxBuf; + m_vo.allocate(data.size() * sizeof(LineEnds), data.data()); + m_vo.setVertices(3, GL_FLOAT, false, sizeof(LineEnds), offsetof(LineEnds, point1)); + m_vo.setVertexAttribArray(CelestiaGLProgram::NextVCoordAttributeIndex, 3, GL_FLOAT, false, sizeof(LineEnds), offsetof(LineEnds, point2)); + m_vo.setVertexAttribArray(CelestiaGLProgram::ScaleFactorAttributeIndex, 1, GL_FLOAT, false, sizeof(LineEnds), offsetof(LineEnds, scale)); } prog->use(); prog->setMVPMatrices(*mvp.projection, *mvp.modelview); + prog->lineWidthX = renderer.getLineWidthX(); + prog->lineWidthY = renderer.getLineWidthY(); glVertexAttrib(CelestiaGLProgram::ColorAttributeIndex, defaultColor); - m_vo.draw(GL_LINES, m_vtxTotal); + m_vo.draw(GL_TRIANGLES, m_vtxTotal); assert(m_asterisms->size() == m_vtxCount.size()); @@ -67,16 +70,16 @@ void AsterismRenderer::render(const Renderer &renderer, const Color &defaultColo continue; } - Color color = {ast->getOverrideColor(), opacity}; + Color color = {ast->getOverrideColor(), opacity}; glVertexAttrib(CelestiaGLProgram::ColorAttributeIndex, color); - m_vo.draw(GL_LINES, m_vtxCount[i], offset); + m_vo.draw(GL_TRIANGLES, m_vtxCount[i], offset); offset += m_vtxCount[i]; } m_vo.unbind(); } -GLfloat* AsterismRenderer::prepare() +bool AsterismRenderer::prepare(std::vector &data) { // calculate required vertices number GLsizei vtx_num = 0; @@ -85,12 +88,12 @@ GLfloat* AsterismRenderer::prepare() GLsizei ast_vtx_num = 0; for (int k = 0; k < ast->getChainCount(); k++) { - // as we use GL_LINES we should double the number of vertices - // as we don't need closed figures we have only one copy of - // the 1st and last vertexes + // as we use GL_TRIANGLES we should six times the number of + // vertices as we don't need closed figures we have only one + // copy of the 1st and last vertexes GLsizei s = ast->getChain(k).size(); if (s > 1) - ast_vtx_num += 2 * s - 2; + ast_vtx_num += (s - 1) * 6; } m_vtxCount.push_back(ast_vtx_num); @@ -98,11 +101,9 @@ GLfloat* AsterismRenderer::prepare() } if (vtx_num == 0) - return nullptr; + return false; m_vtxTotal = vtx_num; - - GLfloat* vtx_buf = new GLfloat[vtx_num * 3]; - GLfloat* ptr = vtx_buf; + data.reserve(m_vtxTotal); for (const auto ast : *m_asterisms) { @@ -114,17 +115,18 @@ GLfloat* AsterismRenderer::prepare() if (chain.size() <= 1) continue; - memcpy(ptr, chain[0].data(), 3 * sizeof(float)); - ptr += 3; - for (unsigned i = 1; i < chain.size() - 1; i++) + for (unsigned i = 1; i < chain.size(); i++) { - memcpy(ptr, chain[i].data(), 3 * sizeof(float)); - memcpy(ptr + 3, chain[i].data(), 3 * sizeof(float)); - ptr += 6; + Eigen::Vector3f prev = chain[i - 1]; + Eigen::Vector3f cur = chain[i]; + data.emplace_back(prev, cur, -0.5); + data.emplace_back(prev ,cur, 0.5); + data.emplace_back(cur, prev, -0.5); + data.emplace_back(cur, prev, -0.5); + data.emplace_back(cur, prev, 0.5); + data.emplace_back(prev, cur, -0.5); } - memcpy(ptr, chain[chain.size() - 1].data(), 3 * sizeof(float)); - ptr += 3; } } - return vtx_buf; + return true; } diff --git a/src/celengine/asterismrenderer.h b/src/celengine/asterismrenderer.h index 4153c7d2a..0fc532e49 100644 --- a/src/celengine/asterismrenderer.h +++ b/src/celengine/asterismrenderer.h @@ -17,6 +17,7 @@ class Renderer; struct Matrices; +struct LineEnds; class AsterismRenderer { @@ -33,7 +34,7 @@ class AsterismRenderer bool sameAsterisms(const AsterismList *asterisms) const; private: - GLfloat* prepare(); + bool prepare(std::vector &data); celgl::VertexObject m_vo { GL_ARRAY_BUFFER, 0, GL_STATIC_DRAW }; ShaderProperties m_shadprop; diff --git a/src/celengine/axisarrow.cpp b/src/celengine/axisarrow.cpp index 65d4d2e43..050379284 100644 --- a/src/celengine/axisarrow.cpp +++ b/src/celengine/axisarrow.cpp @@ -37,7 +37,7 @@ constexpr const float headRadius = 0.025f; constexpr const unsigned nSections = 30; -static size_t initArrowAndLetters(VertexObject &vo) +static size_t initArrow(VertexObject &vo) { static_assert(sizeof(Vector3f) == 3*sizeof(GLfloat), "sizeof(Vector3f) != 3*sizeof(GLfloat)"); static size_t count = 0; // number of vertices in the arrow @@ -122,31 +122,9 @@ static size_t initArrowAndLetters(VertexObject &vo) #endif head.push_back(head[1]); - - GLfloat lettersVtx[] = - { - // X - 0, 0, 0, - 1, 0, 1, - 1, 0, 0, - 0, 0, 1, - // Y - 0, 0, 1, - 0.5f, 0, 0.5f, - 1, 0, 1, - 0.5f, 0, 0.5f, - 0.5f, 0, 0, - 0.5f, 0, 0.5f, - // Z - 0, 0, 1, - 1, 0, 1, - 0, 0, 0, - 1, 0, 0 - }; - GLintptr offset = 0; count = circle.size() + shaft.size() + annulus.size() + head.size(); - GLsizeiptr size = sizeof(lettersVtx) + count * sizeof(GLfloat) * 3; + GLsizeiptr size = count * sizeof(GLfloat) * 3; GLsizeiptr s = 0; vo.allocate(size); @@ -167,16 +145,88 @@ static size_t initArrowAndLetters(VertexObject &vo) vo.setBufferData(head.data(), offset, s); offset += s; - vo.setBufferData(lettersVtx, offset, sizeof(lettersVtx)); - vo.setVertices(3, GL_FLOAT, GL_FALSE, 0, 0); return count; } +static void initLetters(VertexObject &vo) +{ + vo.bind(); + if (vo.initialized()) + return; + + GLfloat lettersVtx[] = + { + // X + 0, 0, 0, 1, 0, 1, -0.5f, + 0, 0, 0, 1, 0, 1, 0.5f, + 1, 0, 1, 0, 0, 0, -0.5f, + 1, 0, 1, 0, 0, 0, -0.5f, + 1, 0, 1, 0, 0, 0, 0.5f, + 0, 0, 0, 1, 0, 1, -0.5f, + + 1, 0, 0, 0, 0, 1, -0.5f, + 1, 0, 0, 0, 0, 1, 0.5f, + 0, 0, 1, 1, 0, 0, -0.5f, + 0, 0, 1, 1, 0, 0, -0.5f, + 0, 0, 1, 1, 0, 0, 0.5f, + 1, 0, 0, 0, 0, 1, -0.5f, + // Y + 0, 0, 1, 0.5f, 0, 0.5f, -0.5f, + 0, 0, 1, 0.5f, 0, 0.5f, 0.5f, + 0.5f, 0, 0.5f, 0, 0, 1, -0.5f, + 0.5f, 0, 0.5f, 0, 0, 1, -0.5f, + 0.5f, 0, 0.5f, 0, 0, 1, 0.5f, + 0, 0, 1, 0.5f, 0, 0.5f, -0.5f, + + 1, 0, 1, 0.5f, 0, 0.5f, -0.5f, + 1, 0, 1, 0.5f, 0, 0.5f, 0.5f, + 0.5f, 0, 0.5f, 1, 0, 1, -0.5f, + 0.5f, 0, 0.5f, 1, 0, 1, -0.5f, + 0.5f, 0, 0.5f, 1, 0, 1, 0.5f, + 1, 0, 1, 0.5f, 0, 0.5f, -0.5f, + + 0.5f, 0, 0, 0.5f, 0, 0.5f, -0.5f, + 0.5f, 0, 0, 0.5f, 0, 0.5f, 0.5f, + 0.5f, 0, 0.5f, 0.5f, 0, 0, -0.5f, + 0.5f, 0, 0.5f, 0.5f, 0, 0, -0.5f, + 0.5f, 0, 0.5f, 0.5f, 0, 0, 0.5f, + 0.5f, 0, 0, 0.5f, 0, 0.5f, -0.5f, + // Z + 0, 0, 1, 1, 0, 1, -0.5f, + 0, 0, 1, 1, 0, 1, 0.5f, + 1, 0, 1, 0, 0, 1, -0.5f, + 1, 0, 1, 0, 0, 1, -0.5f, + 1, 0, 1, 0, 0, 1, 0.5f, + 0, 0, 1, 1, 0, 1, -0.5f, + + 1, 0, 1, 0, 0, 0, -0.5f, + 1, 0, 1, 0, 0, 0, 0.5f, + 0, 0, 0, 1, 0, 1, -0.5f, + 0, 0, 0, 1, 0, 1, -0.5f, + 0, 0, 0, 1, 0, 1, 0.5f, + 1, 0, 1, 0, 0, 0, -0.5f, + + 0, 0, 0, 1, 0, 0, -0.5f, + 0, 0, 0, 1, 0, 0, 0.5f, + 1, 0, 0, 0, 0, 0, -0.5f, + 1, 0, 0, 0, 0, 0, -0.5f, + 1, 0, 0, 0, 0, 0, 0.5f, + 0, 0, 0, 1, 0, 0, -0.5f, + }; + + vo.allocate(sizeof(lettersVtx)); + + vo.setBufferData(lettersVtx, 0, sizeof(lettersVtx)); + vo.setVertices(3, GL_FLOAT, GL_FALSE, sizeof(float) * 7, 0); + vo.setVertexAttribArray(CelestiaGLProgram::NextVCoordAttributeIndex, 3, GL_FLOAT, GL_FALSE, sizeof(float) * 7, sizeof(float) * 3); + vo.setVertexAttribArray(CelestiaGLProgram::ScaleFactorAttributeIndex, 1, GL_FLOAT, GL_FALSE, sizeof(float) * 7, sizeof(float) * 6); +} + static void RenderArrow(VertexObject& vo) { - auto count = initArrowAndLetters(vo); + auto count = initArrow(vo); vo.draw(GL_TRIANGLES, count); vo.unbind(); } @@ -184,8 +234,8 @@ static void RenderArrow(VertexObject& vo) // Draw letter x in xz plane static void RenderX(VertexObject& vo) { - auto offset = initArrowAndLetters(vo); - vo.draw(GL_LINES, 4, offset); + initLetters(vo); + vo.draw(GL_TRIANGLES, 12); vo.unbind(); } @@ -193,8 +243,8 @@ static void RenderX(VertexObject& vo) // Draw letter y in xz plane static void RenderY(VertexObject& vo) { - auto offset = initArrowAndLetters(vo); - vo.draw(GL_LINES, 6, offset+4); + initLetters(vo); + vo.draw(GL_TRIANGLES, 18, 12); vo.unbind(); } @@ -202,8 +252,8 @@ static void RenderY(VertexObject& vo) // Draw letter z in xz plane static void RenderZ(VertexObject& vo) { - auto offset = initArrowAndLetters(vo); - vo.draw(GL_LINE_STRIP, 4, offset+10); + initLetters(vo); + vo.draw(GL_TRIANGLES, 18, 30); vo.unbind(); } @@ -387,35 +437,49 @@ AxesReferenceMark::render(Renderer* renderer, return; prog->use(); - auto &vo = renderer->getVertexObject(VOType::AxisArrow, GL_ARRAY_BUFFER, 0, GL_STATIC_DRAW); + auto &arrowVo = renderer->getVertexObject(VOType::AxisArrow, GL_ARRAY_BUFFER, 0, GL_STATIC_DRAW); Affine3f labelTransform = Translation3f(Vector3f(0.1f, 0.0f, 0.75f)) * Scaling(labelScale); Matrix4f labelTransformMatrix = labelTransform.matrix(); - Matrix4f tModelView; // x-axis - tModelView = modelView * vecgl::rotate(AngleAxisf(90.0_deg, Vector3f::UnitY())); + Matrix4f xModelView = modelView * vecgl::rotate(AngleAxisf(90.0_deg, Vector3f::UnitY())); glVertexAttrib4f(CelestiaGLProgram::ColorAttributeIndex, 1.0f, 0.0f, 0.0f, opacity); - prog->setMVPMatrices(projection, tModelView); - RenderArrow(vo); - prog->setMVPMatrices(projection, tModelView * labelTransformMatrix); - RenderX(vo); + prog->setMVPMatrices(projection, xModelView); + RenderArrow(arrowVo); // y-axis - tModelView = modelView * vecgl::rotate(AngleAxisf(180.0_deg, Vector3f::UnitY())); + Matrix4f yModelView = modelView * vecgl::rotate(AngleAxisf(180.0_deg, Vector3f::UnitY())); glVertexAttrib4f(CelestiaGLProgram::ColorAttributeIndex, 0.0f, 1.0f, 0.0f, opacity); - prog->setMVPMatrices(projection, tModelView); - RenderArrow(vo); - prog->setMVPMatrices(projection, tModelView * labelTransformMatrix); - RenderY(vo); + prog->setMVPMatrices(projection, yModelView); + RenderArrow(arrowVo); // z-axis - tModelView = modelView *vecgl::rotate(AngleAxisf(-90.0_deg, Vector3f::UnitX())); + Matrix4f zModelView = modelView *vecgl::rotate(AngleAxisf(-90.0_deg, Vector3f::UnitX())); glVertexAttrib4f(CelestiaGLProgram::ColorAttributeIndex, 0.0f, 0.0f, 1.0f, opacity); - prog->setMVPMatrices(projection, tModelView); - RenderArrow(vo); - prog->setMVPMatrices(projection, tModelView * labelTransformMatrix); - RenderZ(vo); + prog->setMVPMatrices(projection, zModelView); + RenderArrow(arrowVo); + + ShaderProperties letterProp = shadprop; + letterProp.texUsage |= ShaderProperties::LineAsTriangles; + prog = renderer->getShaderManager().getShader(letterProp); + if (prog == nullptr) + return; + + prog->use(); + prog->lineWidthX = renderer->getLineWidthX(); + prog->lineWidthY = renderer->getLineWidthY(); + + auto &letterVo = renderer->getVertexObject(VOType::AxisLetter, GL_ARRAY_BUFFER, 0, GL_STATIC_DRAW); + glVertexAttrib4f(CelestiaGLProgram::ColorAttributeIndex, 1.0f, 0.0f, 0.0f, opacity); + prog->setMVPMatrices(projection, xModelView * labelTransformMatrix); + RenderX(letterVo); + glVertexAttrib4f(CelestiaGLProgram::ColorAttributeIndex, 0.0f, 1.0f, 0.0f, opacity); + prog->setMVPMatrices(projection, yModelView * labelTransformMatrix); + RenderY(letterVo); + glVertexAttrib4f(CelestiaGLProgram::ColorAttributeIndex, 0.0f, 0.0f, 1.0f, opacity); + prog->setMVPMatrices(projection, zModelView * labelTransformMatrix); + RenderZ(letterVo); renderer->enableBlending(); renderer->setBlendingFactors(GL_SRC_ALPHA, GL_ONE); diff --git a/src/celengine/boundariesrenderer.cpp b/src/celengine/boundariesrenderer.cpp index 685e2348d..22275da3f 100644 --- a/src/celengine/boundariesrenderer.cpp +++ b/src/celengine/boundariesrenderer.cpp @@ -21,7 +21,7 @@ using namespace std; BoundariesRenderer::BoundariesRenderer(const ConstellationBoundaries *boundaries) : m_boundaries(boundaries) { - m_shadprop.texUsage = ShaderProperties::VertexColors; + m_shadprop.texUsage = ShaderProperties::VertexColors | ShaderProperties::LineAsTriangles; m_shadprop.lightModel = ShaderProperties::UnlitModel; } @@ -39,54 +39,57 @@ void BoundariesRenderer::render(const Renderer &renderer, const Color &color, co m_vo.bind(); if (!m_vo.initialized()) { - auto *vtx_buf = prepare(); - if (vtx_buf == nullptr) + std::vector data; + if (!prepare(data)) { m_vo.unbind(); return; } - m_vo.allocate(m_vtxTotal * 3 * sizeof(GLshort), vtx_buf); - m_vo.setVertices(3, GL_SHORT, false, 0, 0); - delete[] vtx_buf; + m_vo.allocate(m_vtxTotal * sizeof(LineEnds), data.data()); + m_vo.setVertices(3, GL_FLOAT, false, sizeof(LineEnds), offsetof(LineEnds, point1)); + m_vo.setVertexAttribArray(CelestiaGLProgram::NextVCoordAttributeIndex, 3, GL_FLOAT, false, sizeof(LineEnds), offsetof(LineEnds, point2)); + m_vo.setVertexAttribArray(CelestiaGLProgram::ScaleFactorAttributeIndex, 1, GL_FLOAT, false, sizeof(LineEnds), offsetof(LineEnds, scale)); } prog->use(); prog->setMVPMatrices(*mvp.projection, *mvp.modelview); + prog->lineWidthX = renderer.getLineWidthX(); + prog->lineWidthY = renderer.getLineWidthY(); glVertexAttrib(CelestiaGLProgram::ColorAttributeIndex, color); - m_vo.draw(GL_LINES, m_vtxTotal); + m_vo.draw(GL_TRIANGLES, m_vtxTotal); m_vo.unbind(); } -GLshort* BoundariesRenderer::prepare() +bool BoundariesRenderer::prepare(std::vector &data) { auto chains = m_boundaries->getChains(); auto vtx_num = accumulate(chains.begin(), chains.end(), 0, [](int a, ConstellationBoundaries::Chain* b) { return a + b->size(); }); if (vtx_num == 0) - return nullptr; + return false; - // as we use GL_LINES we should double the number of vertices - vtx_num *= 2; + // as we use GL_TRIANGLES we should six times the number of vertices + vtx_num *= 6; m_vtxTotal = vtx_num; - auto *vtx_buf = new GLshort[vtx_num * 3]; - GLshort* ptr = vtx_buf; + data.reserve(m_vtxTotal); for (const auto chain : chains) { - for (unsigned j = 0; j < 3; j++, ptr++) - *ptr = (GLshort) (*chain)[0][j]; for (unsigned i = 1; i < chain->size(); i++) { - for (unsigned j = 0; j < 3; j++) - ptr[j] = ptr[j + 3] = (GLshort) (*chain)[i][j]; - ptr += 6; + Eigen::Vector3f prev = (*chain)[i - 1]; + Eigen::Vector3f cur = (*chain)[i]; + data.emplace_back(prev, cur, -0.5); + data.emplace_back(prev ,cur, 0.5); + data.emplace_back(cur, prev, -0.5); + data.emplace_back(cur, prev, -0.5); + data.emplace_back(cur, prev, 0.5); + data.emplace_back(prev, cur, -0.5); } - for (unsigned j = 0; j < 3; j++, ptr++) - *ptr = (GLshort) (*chain)[0][j]; } - return vtx_buf; + return true; } diff --git a/src/celengine/boundariesrenderer.h b/src/celengine/boundariesrenderer.h index 2fd6b9f8d..f1d5dad7e 100644 --- a/src/celengine/boundariesrenderer.h +++ b/src/celengine/boundariesrenderer.h @@ -16,6 +16,7 @@ class Color; class ConstellationBoundaries; class Renderer; struct Matrices; +struct LineEnds; class BoundariesRenderer { @@ -32,7 +33,7 @@ class BoundariesRenderer bool sameBoundaries(const ConstellationBoundaries*) const; private: - GLshort* prepare(); + bool prepare(std::vector &data); celgl::VertexObject m_vo { GL_ARRAY_BUFFER, 0, GL_STATIC_DRAW }; ShaderProperties m_shadprop; diff --git a/src/celengine/curveplot.cpp b/src/celengine/curveplot.cpp index a9d830f75..ea2b6223b 100644 --- a/src/celengine/curveplot.cpp +++ b/src/celengine/curveplot.cpp @@ -165,7 +165,7 @@ public: vbobj(0), currentStripLength(0) { - data = new Vertex[capacity]; + data = new Vertex[(capacity + 1) * 2]; } ~HighPrec_VertexBuffer() @@ -183,6 +183,8 @@ public: glEnableVertexAttribArray(CelestiaGLProgram::VertexCoordAttributeIndex); glEnableVertexAttribArray(CelestiaGLProgram::ColorAttributeIndex); + glEnableVertexAttribArray(CelestiaGLProgram::NextVCoordAttributeIndex); + glEnableVertexAttribArray(CelestiaGLProgram::ScaleFactorAttributeIndex); Vector4f* vertexBase = vbobj ? (Vector4f*) offsetof(Vertex, position) : &data[0].position; glVertexAttribPointer(CelestiaGLProgram::VertexCoordAttributeIndex, @@ -192,6 +194,14 @@ public: glVertexAttribPointer(CelestiaGLProgram::ColorAttributeIndex, 4, GL_FLOAT, GL_FALSE, sizeof(Vertex), colorBase); + float* scaleBase = vbobj ? (float*) offsetof(Vertex, scale) : &data[0].scale; + glVertexAttribPointer(CelestiaGLProgram::ScaleFactorAttributeIndex, + 1, GL_FLOAT, GL_FALSE, sizeof(Vertex), scaleBase); + + Vector4f* nextVertexBase = vbobj ? (Vector4f*) (offsetof(Vertex, position) + (2 * sizeof(Vertex))) : &data[2].position; + glVertexAttribPointer(CelestiaGLProgram::NextVCoordAttributeIndex, + 4, GL_FLOAT, GL_FALSE, sizeof(Vertex), nextVertexBase); + stripLengths.clear(); currentStripLength = 0; currentPosition = 0; @@ -205,6 +215,8 @@ public: { glDisableVertexAttribArray(CelestiaGLProgram::ColorAttributeIndex); glDisableVertexAttribArray(CelestiaGLProgram::VertexCoordAttributeIndex); + glDisableVertexAttribArray(CelestiaGLProgram::NextVCoordAttributeIndex); + glDisableVertexAttribArray(CelestiaGLProgram::ScaleFactorAttributeIndex); glBindBuffer(GL_ARRAY_BUFFER, 0); } #endif @@ -213,16 +225,26 @@ public: inline void vertex(const Vector3d& v) { #if USE_VERTEX_BUFFER - data[currentPosition].position.segment<3>(0) = v.cast(); - data[currentPosition].color = color; + Vector3f pos = v.cast(); + int index = currentPosition * 2; + data[index].position.segment<3>(0) = pos; + data[index].color = color; + data[index].scale = -0.5f; + data[index + 1].position.segment<3>(0) = pos; + data[index + 1].color = color; + data[index + 1].scale = 0.5f; ++currentPosition; ++currentStripLength; if (currentPosition == capacity) { flush(); - data[0].position.segment<3>(0) = v.cast(); + data[0].position.segment<3>(0) = pos; data[0].color = color; + data[0].scale = -0.5f; + data[1].position.segment<3>(0) = pos; + data[1].color = color; + data[1].scale = 0.5f; currentPosition = 1; currentStripLength = 1; } @@ -233,38 +255,32 @@ public: inline void vertex(const Vector4d& v) { -#if USE_VERTEX_BUFFER - data[currentPosition].position = v.cast(); - data[currentPosition].color = color; - ++currentPosition; - ++currentStripLength; - if (currentPosition == capacity) - { - flush(); - - data[0].position = v.cast(); - data[0].color = color; - currentPosition = 1; - currentStripLength = 1; - } -#else - glVertex3dv(v.data()); -#endif + vertex(v, color); } inline void vertex(const Vector4d& v, const Vector4f& color) { #if USE_VERTEX_BUFFER - data[currentPosition].position = v.cast(); - data[currentPosition].color = color; + Vector4f pos = v.cast(); + int index = currentPosition * 2; + data[index].position = pos; + data[index].color = color; + data[index].scale = -0.5f; + data[index + 1].position = pos; + data[index + 1].color = color; + data[index + 1].scale = 0.5f; ++currentPosition; ++currentStripLength; if (currentPosition == capacity) { flush(); - data[0].position = v.cast(); + data[0].position = pos; data[0].color = color; + data[0].scale = -0.5f; + data[1].position = pos; + data[1].color = color; + data[1].scale = 0.5f; currentPosition = 1; currentStripLength = 1; } @@ -284,6 +300,12 @@ public: inline void end() { #if USE_VERTEX_BUFFER + if (currentPosition > 1) + { + int index = currentPosition * 2; + memcpy(&data[index], &data[index - 4], 2 * sizeof(Vertex)); + currentPosition += 1; + } stripLengths.push_back(currentStripLength); currentStripLength = 0; #else @@ -296,7 +318,7 @@ public: #if USE_VERTEX_BUFFER if (currentPosition > 0) { - glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(Vertex) * currentPosition, data); + glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(Vertex) * (currentPosition + 1) * 2, data); // Finish the current line strip if (currentStripLength > 1) @@ -305,8 +327,9 @@ public: unsigned int startIndex = 0; for (vector::const_iterator iter = stripLengths.begin(); iter != stripLengths.end(); ++iter) { - glDrawArrays(GL_LINE_STRIP, startIndex, *iter); - startIndex += *iter; + unsigned int drawCount = *iter * 2; + glDrawArrays(GL_TRIANGLE_STRIP, startIndex, drawCount); + startIndex += drawCount + 2; } currentPosition = 0; @@ -325,7 +348,7 @@ public: glGenBuffers(1, &vbobj); glBindBuffer(GL_ARRAY_BUFFER, vbobj); glBufferData(GL_ARRAY_BUFFER, - capacity * sizeof(Vertex), + (2 * (capacity + 1)) * sizeof(Vertex), nullptr, GL_STREAM_DRAW); } @@ -349,6 +372,7 @@ private: EIGEN_MAKE_ALIGNED_OPERATOR_NEW Vector4f position; Vector4f color; + float scale; }; Vertex* data; GLuint vbobj; diff --git a/src/celengine/glmarker.cpp b/src/celengine/glmarker.cpp index 6603a34f9..264821f1f 100644 --- a/src/celengine/glmarker.cpp +++ b/src/celengine/glmarker.cpp @@ -24,38 +24,7 @@ using namespace celmath; using namespace celestia; using namespace Eigen; - -constexpr const int DiamondOffset = 0; -constexpr const int DiamondCount = 4; -static GLfloat Diamond[DiamondCount * 2] = -{ - 0.0f, 1.0f, - 1.0f, 0.0f, - 0.0f, -1.0f, - -1.0f, 0.0f -}; - -constexpr const int PlusOffset = DiamondOffset + DiamondCount; -constexpr const int PlusCount = 4; -static GLfloat Plus[PlusCount * 2] = -{ - 0.0f, 1.0f, - 0.0f, -1.0f, - 1.0f, 0.0f, - -1.0f, 0.0f -}; - -constexpr const int XOffset = PlusOffset + PlusCount; -constexpr const int XCount = 4; -static GLfloat X[XCount * 2] = -{ - -1.0f, -1.0f, - 1.0f, 1.0f, - 1.0f, -1.0f, - -1.0f, 1.0f -}; - -constexpr const int SquareOffset = XOffset + XCount; +constexpr const int SquareOffset = 0; constexpr const int SquareCount = 4; static GLfloat Square[SquareCount * 2] = { @@ -145,7 +114,7 @@ static GLfloat SelPointer[SelPointerCount * 2] = constexpr const int CrosshairOffset = SelPointerOffset + SelPointerCount; constexpr const int CrosshairCount = 3; -static GLfloat Crosshair[CrosshairCount * 2 ] = +static GLfloat Crosshair[CrosshairCount * 2] = { 0.0f, 0.0f, 1.0f, -1.0f, @@ -155,49 +124,117 @@ static GLfloat Crosshair[CrosshairCount * 2 ] = constexpr const int StaticVtxCount = CrosshairOffset + CrosshairCount; constexpr const int SmallCircleOffset = StaticVtxCount; -static int SmallCircleCount = 0; -static int LargeCircleOffset = 0; -static int LargeCircleCount = 0; -static int EclipticOffset = 0; -constexpr const int EclipticCount = 200; +constexpr const int SmallCircleCount = 10; +constexpr const int LargeCircleOffset = SmallCircleOffset + SmallCircleCount; +constexpr const int LargeCircleCount = 60; + +static int DiamondLineOffset = 0; +static int DiamondLineCount = 0; +static int PlusLineOffset = 0; +static int PlusLineCount = 0; +static int XLineOffset = 0; +static int XLineCount = 0; +static int TriangleLineOffset = 0; +static int TriangleLineCount = 0; +static int SquareLineOffset = 0; +static int SquareLineCount = 0; +static int SmallCircleLineOffset = 0; +static int SmallCircleLineCount = 0; +static int LargeCircleLineOffset = 0; +static int LargeCircleLineCount = 0; +static int EclipticLineCount = 0; + +static void fillCircleValue(GLfloat* data, int size, float scale) +{ + float s, c; + for (int i = 0; i < size; i++) + { + sincos((float) (2 * i) / (float) size * ((float) PI), s, c); + data[i * 2] = c * scale; + data[i * 2 + 1] = s * scale; + } +} + +static int bufferVertices(VertexObject& vo, GLfloat* data, int vertexCount, int& offset) +{ + int dataSize = vertexCount * 2 * sizeof(GLfloat); + vo.setBufferData(data, offset, dataSize); + offset += dataSize; + return vertexCount; +} + +static int bufferLineVertices(VertexObject& vo, GLfloat* data, int vertexSize, int vertexCount, int& offset) +{ + int dataSize = vertexCount * 3 * (2 * vertexSize + 1) * sizeof(GLfloat); + GLfloat* tranformed = new GLfloat[dataSize]; + GLfloat* ptr = tranformed; + for (int i = 0; i < vertexCount; i += 2) + { + int index = i * vertexSize; + GLfloat* thisVert = &data[index]; + GLfloat* nextVert = &data[index + vertexSize]; +#define STREAM_AND_ADVANCE(firstVertex, secondVertex, scale) do {\ +memcpy(ptr, firstVertex, vertexSize * sizeof(GLfloat));\ +memcpy(ptr + vertexSize, secondVertex, vertexSize * sizeof(GLfloat));\ +ptr[2 * vertexSize] = scale;\ +ptr += 2 * vertexSize + 1;\ +} while (0) + STREAM_AND_ADVANCE(thisVert, nextVert, -0.5); + STREAM_AND_ADVANCE(thisVert, nextVert, 0.5); + STREAM_AND_ADVANCE(nextVert, thisVert, -0.5); + STREAM_AND_ADVANCE(nextVert, thisVert, -0.5); + STREAM_AND_ADVANCE(nextVert, thisVert, 0.5); + STREAM_AND_ADVANCE(thisVert, nextVert, -0.5); +#undef STREAM_AND_ADVANCE + } + vo.setBufferData(tranformed, offset, dataSize); + offset += dataSize; + delete[] tranformed; + return vertexCount * 3; +} + +static int bufferLineLoopVertices(VertexObject& vo, GLfloat* data, int vertexSize, int vertexCount, int& offset) +{ + int dataSize = vertexCount * 6 * (2 * vertexSize + 1) * sizeof(GLfloat); + GLfloat* tranformed = new GLfloat[dataSize]; + GLfloat* ptr = tranformed; + for (int i = 0; i < vertexCount; i += 1) + { + int index = i * vertexSize; + int nextIndex = ((i + 1) % vertexCount) * vertexSize; + GLfloat* thisVert = &data[index]; + GLfloat* nextVert = &data[nextIndex]; +#define STREAM_AND_ADVANCE(firstVertex, secondVertex, scale) do {\ +memcpy(ptr, firstVertex, vertexSize * sizeof(GLfloat));\ +memcpy(ptr + vertexSize, secondVertex, vertexSize * sizeof(GLfloat));\ +ptr[2 * vertexSize] = scale;\ +ptr += 2 * vertexSize + 1;\ +} while (0) + STREAM_AND_ADVANCE(thisVert, nextVert, -0.5); + STREAM_AND_ADVANCE(thisVert, nextVert, 0.5); + STREAM_AND_ADVANCE(nextVert, thisVert, -0.5); + STREAM_AND_ADVANCE(nextVert, thisVert, -0.5); + STREAM_AND_ADVANCE(nextVert, thisVert, 0.5); + STREAM_AND_ADVANCE(thisVert, nextVert, -0.5); +#undef STREAM_AND_ADVANCE + } + vo.setBufferData(tranformed, offset, dataSize); + offset += dataSize; + delete[] tranformed; + return vertexCount * 6; +} static void initVO(VertexObject& vo) { - float c, s; + GLfloat SmallCircle[SmallCircleCount * 2]; + GLfloat LargeCircle[LargeCircleCount * 2]; + fillCircleValue(SmallCircle, SmallCircleCount, 1.0f); + fillCircleValue(LargeCircle, LargeCircleCount, 1.0f); - vector small, large; - for (int i = 0; i < 360; i += 36) - { - sincos(degToRad(static_cast(i)), s, c); - small.push_back(c); small.push_back(s); - large.push_back(c); large.push_back(s); - for (int j = i+6; j < i+36; j += 6) - { - sincos(degToRad(static_cast(j)), s, c); - large.push_back(c); large.push_back(s); - } - }; + vo.allocate((LargeCircleOffset + LargeCircleCount) * sizeof(GLfloat) * 2); - SmallCircleCount = small.size() / 2; - LargeCircleCount = large.size() / 2; - LargeCircleOffset = SmallCircleOffset + SmallCircleCount; - - vector ecliptic; - for (int i = 0; i < EclipticCount; i++) - { - sincos((float) (2 * i) / (float) EclipticCount * ((float) PI), s, c); - ecliptic.push_back(c * 1000.0f); - ecliptic.push_back(s * 1000.0f); - } - EclipticOffset = LargeCircleOffset + LargeCircleCount; - -#define VTXTOMEM(a) ((a) * sizeof(GLfloat) * 2) - vo.allocate(VTXTOMEM(StaticVtxCount + SmallCircleCount + LargeCircleCount + EclipticCount)); - -#define VOSTREAM(a) vo.setBufferData(a, VTXTOMEM(a ## Offset), sizeof(a)) - VOSTREAM(Diamond); - VOSTREAM(Plus); - VOSTREAM(X); + int offset = 0; +#define VOSTREAM(a) bufferVertices(vo, a, a##Count, offset) VOSTREAM(Square); VOSTREAM(Triangle); VOSTREAM(RightArrow); @@ -206,57 +243,162 @@ static void initVO(VertexObject& vo) VOSTREAM(DownArrow); VOSTREAM(SelPointer); VOSTREAM(Crosshair); + VOSTREAM(SmallCircle); + VOSTREAM(LargeCircle); #undef VOSTREAM - vo.setBufferData(small.data(), VTXTOMEM(SmallCircleOffset), memsize(small)); - vo.setBufferData(large.data(), VTXTOMEM(LargeCircleOffset), memsize(large)); - vo.setBufferData(ecliptic.data(), VTXTOMEM(EclipticOffset), memsize(ecliptic)); -#undef VTXTOMEM - vo.setVertices(2, GL_FLOAT, false, 0, 0); } +static void initLineVO(VertexObject& vo) +{ + constexpr const int DiamondCount = 4; + static GLfloat Diamond[DiamondCount * 2] = + { + 0.0f, 1.0f, + 1.0f, 0.0f, + 0.0f, -1.0f, + -1.0f, 0.0f + }; + constexpr const int PlusCount = 4; + GLfloat Plus[PlusCount * 2] = + { + 0.0f, 1.0f, + 0.0f, -1.0f, + 1.0f, 0.0f, + -1.0f, 0.0f + }; + constexpr const int XCount = 4; + GLfloat X[XCount * 2] = + { + -1.0f, -1.0f, + 1.0f, 1.0f, + 1.0f, -1.0f, + -1.0f, 1.0f + }; + + GLfloat SmallCircle[SmallCircleCount * 2]; + GLfloat LargeCircle[LargeCircleCount * 2]; + fillCircleValue(SmallCircle, SmallCircleCount, 1.0f); + fillCircleValue(LargeCircle, LargeCircleCount, 1.0f); + + int stride = sizeof(GLfloat) * 5; + int size = ((DiamondCount + SquareCount + TriangleCount + SmallCircleCount + LargeCircleCount) * 6 + (PlusCount + XCount) * 3) * stride; + + vo.allocate(size); + + int offset = 0; +#define VOSTREAM_LINES(a) do { \ +a##LineOffset = offset / stride;\ +a##LineCount = bufferLineVertices(vo, a, 2, a##Count, offset); \ +} while (0) +#define VOSTREAM_LINE_LOOP(a) do { \ +a##LineOffset = offset / stride;\ +a##LineCount = bufferLineLoopVertices(vo, a, 2, a##Count, offset); \ +} while (0) + VOSTREAM_LINE_LOOP(Diamond); + VOSTREAM_LINES(Plus); + VOSTREAM_LINES(X); + VOSTREAM_LINE_LOOP(Square); + VOSTREAM_LINE_LOOP(Triangle); + VOSTREAM_LINE_LOOP(SmallCircle); + VOSTREAM_LINE_LOOP(LargeCircle); +#undef VOSTREAM_LINES +#undef VOSTREAM_LINE_LOOP + + vo.setVertices(2, GL_FLOAT, false, stride, 0); + vo.setVertexAttribArray(CelestiaGLProgram::NextVCoordAttributeIndex, 2, GL_FLOAT, false, stride, sizeof(GLfloat) * 2); + vo.setVertexAttribArray(CelestiaGLProgram::ScaleFactorAttributeIndex, 1, GL_FLOAT, false, stride, sizeof(GLfloat) * 4); +} + +static void initEclipticVO(VertexObject& vo) +{ + constexpr const int eclipticCount = 200; + GLfloat ecliptic[eclipticCount * 3]; + float s, c; + float scale = 1000.0f; + for (int i = 0; i < eclipticCount; i++) + { + sincos((float) (2 * i) / (float) eclipticCount * ((float) PI), s, c); + ecliptic[i * 3] = c * scale; + ecliptic[i * 3 + 1] = 0; + ecliptic[i * 3 + 2] = s * scale; + } + + int stride = sizeof(GLfloat) * 7; + vo.allocate(eclipticCount * 6 * stride); + int offset = 0; + EclipticLineCount = bufferLineLoopVertices(vo, ecliptic, 3, eclipticCount, offset); + + vo.setVertices(3, GL_FLOAT, false, stride, 0); + vo.setVertexAttribArray(CelestiaGLProgram::NextVCoordAttributeIndex, 3, GL_FLOAT, false, stride, sizeof(GLfloat) * 3); + vo.setVertexAttribArray(CelestiaGLProgram::ScaleFactorAttributeIndex, 1, GL_FLOAT, false, stride, sizeof(GLfloat) * 6); +} + void Renderer::renderMarker(MarkerRepresentation::Symbol symbol, float size, const Color &color, const Matrices &m) { assert(shaderManager != nullptr); + + bool solid = true; + + switch (symbol) + { + case MarkerRepresentation::Diamond: + case MarkerRepresentation::Plus: + case MarkerRepresentation::X: + case MarkerRepresentation::Square: + case MarkerRepresentation::Triangle: + case MarkerRepresentation::Circle: + solid = false; + default: + break; + } + ShaderProperties shadprop; shadprop.texUsage = ShaderProperties::VertexColors; + if (!solid) + shadprop.texUsage |= ShaderProperties::LineAsTriangles; shadprop.lightModel = ShaderProperties::UnlitModel; shadprop.fishEyeOverride = ShaderProperties::FisheyeOverrideModeDisabled; auto* prog = shaderManager->getShader(shadprop); if (prog == nullptr) return; - auto &markerVO = getVertexObject(VOType::Marker, GL_ARRAY_BUFFER, 0, GL_STATIC_DRAW); + auto &markerVO = getVertexObject(solid ? VOType::Marker : VOType::MarkerLine, GL_ARRAY_BUFFER, 0, GL_STATIC_DRAW); markerVO.bind(); if (!markerVO.initialized()) - initVO(markerVO); + solid ? initVO(markerVO) : initLineVO(markerVO); glVertexAttrib(CelestiaGLProgram::ColorAttributeIndex, color); prog->use(); - float s = size / 2.0f; + float s = size / 2.0f * getScaleFactor(); prog->setMVPMatrices(*m.projection, (*m.modelview) * vecgl::scale(Vector3f(s, s, 0))); + if (!solid) + { + prog->lineWidthX = getLineWidthX(); + prog->lineWidthY = getLineWidthY(); + } switch (symbol) { case MarkerRepresentation::Diamond: - markerVO.draw(GL_LINE_LOOP, DiamondCount, DiamondOffset); + markerVO.draw(GL_TRIANGLES, DiamondLineCount, DiamondLineOffset); break; case MarkerRepresentation::Plus: - markerVO.draw(GL_LINES, PlusCount, PlusOffset); + markerVO.draw(GL_TRIANGLES, PlusLineCount, PlusLineOffset); break; case MarkerRepresentation::X: - markerVO.draw(GL_LINES, XCount, XOffset); + markerVO.draw(GL_TRIANGLES, XLineCount, XLineOffset); break; case MarkerRepresentation::Square: - markerVO.draw(GL_LINE_LOOP, SquareCount, SquareOffset); + markerVO.draw(GL_TRIANGLES, SquareLineCount, SquareLineOffset); break; case MarkerRepresentation::FilledSquare: @@ -264,7 +406,7 @@ void Renderer::renderMarker(MarkerRepresentation::Symbol symbol, break; case MarkerRepresentation::Triangle: - markerVO.draw(GL_LINE_LOOP, TriangleCount, TriangleOffset); + markerVO.draw(GL_TRIANGLES, TriangleLineCount, TriangleLineOffset); break; case MarkerRepresentation::RightArrow: @@ -284,14 +426,14 @@ void Renderer::renderMarker(MarkerRepresentation::Symbol symbol, break; case MarkerRepresentation::Circle: - if (s <= 20) - markerVO.draw(GL_LINE_LOOP, SmallCircleCount, SmallCircleOffset); + if (size <= 40.0f) // TODO: this should be configurable + markerVO.draw(GL_TRIANGLES, SmallCircleLineCount, SmallCircleLineOffset); else - markerVO.draw(GL_LINE_LOOP, LargeCircleCount, LargeCircleOffset); + markerVO.draw(GL_TRIANGLES, LargeCircleLineCount, LargeCircleLineOffset); break; case MarkerRepresentation::Disk: - if (s <= 20) // TODO: this should be configurable + if (size <= 40.0f) // TODO: this should be configurable markerVO.draw(GL_TRIANGLE_FAN, SmallCircleCount, SmallCircleOffset); else markerVO.draw(GL_TRIANGLE_FAN, LargeCircleCount, LargeCircleOffset); @@ -365,7 +507,7 @@ void Renderer::renderSelectionPointer(const Observer& observer, const Vector3f ¢er = cameraMatrix.col(2); prog->setMVPMatrices(getProjectionMatrix(), getModelViewMatrix() * vecgl::translate(Vector3f(-center))); prog->vec4Param("color") = Color(SelectionCursorColor, 0.6f).toVector4(); - prog->floatParam("pixelSize") = pixelSize; + prog->floatParam("pixelSize") = pixelSize * getScaleFactor(); prog->floatParam("s") = s; prog->floatParam("c") = c; prog->floatParam("x0") = x0; @@ -390,22 +532,27 @@ void Renderer::renderEclipticLine() if ((renderFlags & ShowEcliptic) == 0) return; - assert(shaderManager != nullptr); - auto* prog = shaderManager->getShader("ecliptic"); + ShaderProperties shadprop; + shadprop.texUsage = ShaderProperties::VertexColors | ShaderProperties::LineAsTriangles; + shadprop.lightModel = ShaderProperties::UnlitModel; + auto* prog = shaderManager->getShader(shadprop); if (prog == nullptr) return; - auto &markerVO = getVertexObject(VOType::Marker, GL_ARRAY_BUFFER, 0, GL_STATIC_DRAW); - markerVO.bind(); - if (!markerVO.initialized()) - initVO(markerVO); + auto &eclipticVO = getVertexObject(VOType::Ecliptic, GL_ARRAY_BUFFER, 0, GL_STATIC_DRAW); + eclipticVO.bind(); + if (!eclipticVO.initialized()) + initEclipticVO(eclipticVO); + + glVertexAttrib(CelestiaGLProgram::ColorAttributeIndex, EclipticColor); prog->use(); prog->setMVPMatrices(getProjectionMatrix(), getModelViewMatrix()); - prog->vec4Param("color") = EclipticColor.toVector4(); - markerVO.draw(GL_LINE_LOOP, EclipticCount, EclipticOffset); + prog->lineWidthX = getLineWidthX(); + prog->lineWidthY = getLineWidthY(); + eclipticVO.draw(GL_TRIANGLES, EclipticLineCount, 0); - markerVO.unbind(); + eclipticVO.unbind(); } void Renderer::renderCrosshair(float selectionSizeInPixels, @@ -439,8 +586,9 @@ void Renderer::renderCrosshair(float selectionSizeInPixels, prog->setMVPMatrices(*m.projection, *m.modelview); prog->vec4Param("color") = color.toVector4(); prog->floatParam("radius") = cursorRadius; - prog->floatParam("width") = minCursorWidth * cursorGrow; - prog->floatParam("h") = 2.0f * cursorGrow; + float scaleFactor = getScaleFactor(); + prog->floatParam("width") = minCursorWidth * cursorGrow * scaleFactor; + prog->floatParam("h") = 2.0f * cursorGrow * scaleFactor; const unsigned int markCount = 4; for (unsigned int i = 0; i < markCount; i++) diff --git a/src/celengine/planetgrid.cpp b/src/celengine/planetgrid.cpp index c0c7e0744..922546cb1 100644 --- a/src/celengine/planetgrid.cpp +++ b/src/celengine/planetgrid.cpp @@ -25,14 +25,14 @@ using namespace celestia; unsigned int PlanetographicGrid::circleSubdivisions = 100; -float* PlanetographicGrid::xyCircle = nullptr; -float* PlanetographicGrid::xzCircle = nullptr; +std::vector PlanetographicGrid::xyCircle; +std::vector PlanetographicGrid::xzCircle; PlanetographicGrid::PlanetographicGrid(const Body& _body) : body(_body) { - if (xyCircle == nullptr) + if (xyCircle.empty()) InitializeGeometry(); setTag("planetographic grid"); setIAULongLatConvention(); @@ -93,7 +93,7 @@ PlanetographicGrid::render(Renderer* renderer, const Matrices& m) const { ShaderProperties shadprop; - shadprop.texUsage = ShaderProperties::VertexColors; + shadprop.texUsage = ShaderProperties::VertexColors | ShaderProperties::LineAsTriangles; shadprop.lightModel = ShaderProperties::UnlitModel; auto *prog = renderer->getShaderManager().getShader(shadprop); if (prog == nullptr) @@ -129,8 +129,14 @@ PlanetographicGrid::render(Renderer* renderer, Matrix4f modelView = *m.modelview * transform.matrix(); glEnableVertexAttribArray(CelestiaGLProgram::VertexCoordAttributeIndex); + glEnableVertexAttribArray(CelestiaGLProgram::NextVCoordAttributeIndex); + glEnableVertexAttribArray(CelestiaGLProgram::ScaleFactorAttributeIndex); glVertexAttribPointer(CelestiaGLProgram::VertexCoordAttributeIndex, - 3, GL_FLOAT, GL_FALSE, 0, xzCircle); + 3, GL_FLOAT, GL_FALSE, sizeof(LineStripEnd), &xzCircle[0].point); + glVertexAttribPointer(CelestiaGLProgram::NextVCoordAttributeIndex, + 3, GL_FLOAT, GL_FALSE, sizeof(LineStripEnd), &xzCircle[2].point); + glVertexAttribPointer(CelestiaGLProgram::ScaleFactorAttributeIndex, + 1, GL_FLOAT, GL_FALSE, sizeof(LineStripEnd), &xzCircle[0].scale); // Only show the coordinate labels if the body is sufficiently large on screen bool showCoordinateLabels = false; @@ -146,6 +152,8 @@ PlanetographicGrid::render(Renderer* renderer, } prog->use(); + float lineWidthX = renderer->getLineWidthX(); + float lineWidthY = renderer->getLineWidthY(); for (float latitude = -90.0f + latitudeStep; latitude < 90.0f; latitude += latitudeStep) { @@ -156,17 +164,18 @@ PlanetographicGrid::render(Renderer* renderer, { glVertexAttrib(CelestiaGLProgram::ColorAttributeIndex, Renderer::PlanetEquatorColor); - glLineWidth(2.0f * renderer->getScreenDpi() / 96.0f); + prog->lineWidthX = 2.0f * lineWidthX; + prog->lineWidthY = 2.0f * lineWidthY; } else { glVertexAttrib(CelestiaGLProgram::ColorAttributeIndex, Renderer::PlanetographicGridColor); + prog->lineWidthX = lineWidthX; + prog->lineWidthY = lineWidthY; } prog->setMVPMatrices(projection, modelView * vecgl::translate(0.0f, sin(phi), 0.0f) * vecgl::scale(r)); - glDrawArrays(GL_LINE_LOOP, 0, circleSubdivisions); - - glLineWidth(1.0f * renderer->getScreenDpi() / 96.0f); + glDrawArrays(GL_TRIANGLE_STRIP, 0, xzCircle.size() - 2); if (showCoordinateLabels) { @@ -186,14 +195,18 @@ PlanetographicGrid::render(Renderer* renderer, } glVertexAttribPointer(CelestiaGLProgram::VertexCoordAttributeIndex, - 3, GL_FLOAT, GL_FALSE, 0, xyCircle); + 3, GL_FLOAT, GL_FALSE, sizeof(LineStripEnd), &xyCircle[0].point); + glVertexAttribPointer(CelestiaGLProgram::NextVCoordAttributeIndex, + 3, GL_FLOAT, GL_FALSE, sizeof(LineStripEnd), &xyCircle[2].point); + glVertexAttribPointer(CelestiaGLProgram::ScaleFactorAttributeIndex, + 1, GL_FLOAT, GL_FALSE, sizeof(LineStripEnd), &xyCircle[0].scale); glVertexAttrib(CelestiaGLProgram::ColorAttributeIndex, Renderer::PlanetographicGridColor); for (float longitude = 0.0f; longitude <= 180.0f; longitude += longitudeStep) { prog->setMVPMatrices(projection, modelView * vecgl::rotate(AngleAxisf(degToRad(longitude), Vector3f::UnitY()))); - glDrawArrays(GL_LINE_LOOP, 0, circleSubdivisions); + glDrawArrays(GL_TRIANGLE_STRIP, 0, xyCircle.size() - 2); if (showCoordinateLabels) { @@ -247,6 +260,8 @@ PlanetographicGrid::render(Renderer* renderer, } glDisableVertexAttribArray(CelestiaGLProgram::VertexCoordAttributeIndex); + glDisableVertexAttribArray(CelestiaGLProgram::NextVCoordAttributeIndex); + glDisableVertexAttribArray(CelestiaGLProgram::ScaleFactorAttributeIndex); renderer->enableBlending(); renderer->setBlendingFactors(GL_SRC_ALPHA, GL_ONE); @@ -291,18 +306,18 @@ PlanetographicGrid::setIAULongLatConvention() void PlanetographicGrid::InitializeGeometry() { - xyCircle = new float[circleSubdivisions * 3]; - xzCircle = new float[circleSubdivisions * 3]; - for (unsigned int i = 0; i < circleSubdivisions; i++) + xyCircle.reserve((circleSubdivisions + 2) * 2); + xzCircle.reserve((circleSubdivisions + 2) * 2); + for (unsigned int i = 0; i <= circleSubdivisions + 1; i++) { float theta = (float) (2.0 * PI) * (float) i / (float) circleSubdivisions; float s, c; sincos(theta, s, c); - xyCircle[i * 3 + 0] = c; - xyCircle[i * 3 + 1] = s; - xyCircle[i * 3 + 2] = 0.0f; - xzCircle[i * 3 + 0] = c; - xzCircle[i * 3 + 1] = 0.0f; - xzCircle[i * 3 + 2] = s; + Vector3f thisPointXY(c, s, 0.0f); + Vector3f thisPointXZ(c, 0.0f, s); + xyCircle.emplace_back(thisPointXY, -0.5f); + xyCircle.emplace_back(thisPointXY, 0.5f); + xzCircle.emplace_back(thisPointXZ, -0.5f); + xzCircle.emplace_back(thisPointXZ, 0.5f); } } diff --git a/src/celengine/planetgrid.h b/src/celengine/planetgrid.h index 94b93de84..6a80a4d4e 100644 --- a/src/celengine/planetgrid.h +++ b/src/celengine/planetgrid.h @@ -16,7 +16,7 @@ #include class Body; - +struct LineStripEnd; class PlanetographicGrid : public ReferenceMark { @@ -71,8 +71,8 @@ private: NorthDirection northDirection{ NorthNormal }; static unsigned int circleSubdivisions; - static float* xyCircle; - static float* xzCircle; + static std::vector xyCircle; + static std::vector xzCircle; }; #endif // _CELENGINE_PLANETGRID_H_ diff --git a/src/celengine/rendcontext.cpp b/src/celengine/rendcontext.cpp index 111dde2c0..5a0b10a25 100644 --- a/src/celengine/rendcontext.cpp +++ b/src/celengine/rendcontext.cpp @@ -162,8 +162,11 @@ RenderContext::drawGroup(const Mesh::PrimitiveGroup& group) return; } + bool drawPoints = false; + bool drawLines = false; if (group.prim == Mesh::SpriteList || group.prim == Mesh::PointList) { + drawPoints = true; if (group.prim == Mesh::PointList) glVertexAttrib1f(CelestiaGLProgram::PointSizeAttributeIndex, 1.0f); #ifndef GL_ES @@ -172,17 +175,26 @@ RenderContext::drawGroup(const Mesh::PrimitiveGroup& group) #endif glActiveTexture(GL_TEXTURE0); } + else if (group.prim == Mesh::LineList || group.prim == Mesh::LineStrip) + { + drawLines = true; + renderer->enableSmoothLines(); + } glDrawElements(GLPrimitiveModes[(int) group.prim], group.nIndices, GL_UNSIGNED_INT, group.indices); #ifndef GL_ES - if (group.prim == Mesh::SpriteList || group.prim == Mesh::PointList) + if (drawPoints) { glDisable(GL_POINT_SPRITE); glDisable(GL_VERTEX_PROGRAM_POINT_SIZE); } + else if (drawLines) + { + renderer->disableSmoothLines(); + } #endif } diff --git a/src/celengine/render.cpp b/src/celengine/render.cpp index e30e6952b..ef6c9a646 100644 --- a/src/celengine/render.cpp +++ b/src/celengine/render.cpp @@ -701,6 +701,31 @@ void Renderer::setScreenDpi(int _dpi) screenDpi = _dpi; } +float Renderer::getScaleFactor() const +{ + return screenDpi / 96.0f; +} + +float Renderer::getPointWidth() const +{ + return 2.0f / windowWidth * getScaleFactor(); +} + +float Renderer::getPointHeight() const +{ + return 2.0f / windowHeight * getScaleFactor(); +} + +float Renderer::getLineWidthX() const +{ + return ((renderFlags | ShowSmoothLines) ? 1.5f : 1.0f) * getPointWidth(); +} + +float Renderer::getLineWidthY() const +{ + return ((renderFlags | ShowSmoothLines) ? 1.5f : 1.0f) * getPointHeight(); +} + void Renderer::setFaintestAM45deg(float _faintestAutoMag45deg) { faintestAutoMag45deg = _faintestAutoMag45deg; @@ -1033,7 +1058,7 @@ Renderer::enableSmoothLines() #ifndef GL_ES glEnable(GL_LINE_SMOOTH); #endif - glLineWidth(1.5f * screenDpi / 96.0f); + glLineWidth(1.5f * getScaleFactor()); } void @@ -1047,7 +1072,7 @@ Renderer::disableSmoothLines() #ifndef GL_ES glDisable(GL_LINE_SMOOTH); #endif - glLineWidth(1.0f * screenDpi / 96.0f); + glLineWidth(1.0f * getScaleFactor()); } Vector4f renderOrbitColor(const Body *body, bool selected, float opacity) @@ -1117,7 +1142,7 @@ void Renderer::renderOrbit(const OrbitPathListEntry& orbitPath, const Matrices& m) { ShaderProperties shadprop; - shadprop.texUsage = ShaderProperties::VertexColors; + shadprop.texUsage = ShaderProperties::VertexColors | ShaderProperties::LineAsTriangles; shadprop.lightModel = ShaderProperties::UnlitModel; auto *prog = shaderManager->getShader(shadprop); if (prog == nullptr) @@ -1320,6 +1345,8 @@ void Renderer::renderOrbit(const OrbitPathListEntry& orbitPath, prog->use(); prog->setMVPMatrices(*m.projection); + prog->lineWidthX = getPointWidth(); + prog->lineWidthY = getPointHeight(); if (orbit->isPeriodic()) { double period = orbit->getPeriod(); @@ -1722,9 +1749,7 @@ void Renderer::draw(const Observer& observer, disableDepthMask(); // Render sky grids first--these will always be in the background - enableSmoothLines(); renderSkyGrids(observer); - disableSmoothLines(); enableBlending(); // Render deep sky objects @@ -3869,9 +3894,7 @@ void Renderer::renderAsterisms(const Universe& universe, float dist, const Matri (MaxAsterismLinesDist - MaxAsterismLinesConstDist) + 1); } - enableSmoothLines(); m_asterismRenderer->render(*this, Color(ConstellationColor, opacity), mvp); - disableSmoothLines(); } @@ -3900,9 +3923,7 @@ void Renderer::renderBoundaries(const Universe& universe, float dist, const Matr (MaxAsterismLabelsDist - MaxAsterismLabelsConstDist) + 1); } - enableSmoothLines(); m_boundariesRenderer->render(*this, Color(BoundaryColor, opacity), mvp); - disableSmoothLines(); } @@ -4689,10 +4710,6 @@ void Renderer::renderDeepSkyObjects(const Universe& universe, openClusterRep = MarkerRepresentation(MarkerRepresentation::Circle, 8.0f, OpenClusterLabelColor); globularRep = MarkerRepresentation(MarkerRepresentation::Circle, 8.0f, GlobularLabelColor); - // Render any line primitives with smooth lines - // (mostly to make graticules look good.) - enableSmoothLines(); - setBlendingFactors(GL_SRC_ALPHA, GL_ONE); #ifdef OCTREE_DEBUG @@ -4713,8 +4730,6 @@ void Renderer::renderDeepSkyObjects(const Universe& universe, #endif // clog << "DSOs processed: " << dsoRenderer.dsosProcessed << endl; - - disableSmoothLines(); } @@ -4946,9 +4961,6 @@ void Renderer::renderAnnotations(const vector& annotations, if (font[fs] == nullptr) return; - // Enable line smoothing for rendering symbols - enableSmoothLines(); - #ifdef USE_HDR glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_FALSE); #endif @@ -5010,7 +5022,6 @@ void Renderer::renderAnnotations(const vector& annotations, #endif font[fs]->unbind(); - disableSmoothLines(); } @@ -5444,10 +5455,14 @@ void Renderer::drawRectangle(const Rect &r, int fishEyeOverrideMode, const Eigen ShaderProperties shadprop; shadprop.lightModel = ShaderProperties::UnlitModel; + bool solid = r.type != Rect::Type::BorderOnly; + if (r.nColors > 0) shadprop.texUsage |= ShaderProperties::VertexColors; if (r.tex != nullptr) shadprop.texUsage |= ShaderProperties::DiffuseTexture; + if (!solid) + shadprop.texUsage |= ShaderProperties::LineAsTriangles; shadprop.fishEyeOverride = fishEyeOverrideMode; @@ -5457,10 +5472,55 @@ void Renderer::drawRectangle(const Rect &r, int fishEyeOverrideMode, const Eigen constexpr array texels = {0, 1, 1, 1, 1, 0, 0, 0}; array vertices = { r.x, r.y, r.x+r.w, r.y, r.x+r.w, r.y+r.h, r.x, r.y+r.h }; + array lineAsTriangleVertices = { + r.x, r.y, r.x + r.w, r.y, -0.5, + r.x, r.y, r.x + r.w, r.y, 0.5, + + r.x + r.w, r.y, r.x, r.y, -0.5, + r.x + r.w, r.y, r.x, r.y, 0.5, + + r.x + r.w, r.y, r.x + r.w, r.y + r.h, -0.5, + r.x + r.w, r.y, r.x + r.w, r.y + r.h, 0.5, + + r.x + r.w, r.y + r.h, r.x + r.w, r.y, -0.5, + r.x + r.w, r.y + r.h, r.x + r.w, r.y, 0.5, + + r.x + r.w, r.y + r.h, r.x, r.y + r.h, -0.5, + r.x + r.w, r.y + r.h, r.x, r.y + r.h, 0.5, + + r.x, r.y + r.h, r.x + r.w, r.y + r.h, -0.5, + r.x, r.y + r.h, r.x + r.w, r.y + r.h, 0.5, + + r.x, r.y + r.h, r.x, r.y, -0.5, + r.x, r.y + r.h, r.x, r.y, 0.5, + + r.x, r.y, r.x, r.y + r.h, -0.5, + r.x, r.y, r.x, r.y + r.h, 0.5, + }; + constexpr array lineAsTriangleIndcies = { + 0, 1, 2, 2, 3, 0, + 4, 5, 6, 6, 7, 4, + 8, 9, 10, 10, 11, 8, + 12, 13, 14, 14, 15, 12 + }; glEnableVertexAttribArray(CelestiaGLProgram::VertexCoordAttributeIndex); - glVertexAttribPointer(CelestiaGLProgram::VertexCoordAttributeIndex, - 2, GL_FLOAT, GL_FALSE, 0, vertices.data()); + if (solid) + { + glVertexAttribPointer(CelestiaGLProgram::VertexCoordAttributeIndex, + 2, GL_FLOAT, GL_FALSE, 0, vertices.data()); + } + else + { + glEnableVertexAttribArray(CelestiaGLProgram::NextVCoordAttributeIndex); + glEnableVertexAttribArray(CelestiaGLProgram::ScaleFactorAttributeIndex); + glVertexAttribPointer(CelestiaGLProgram::VertexCoordAttributeIndex, + 2, GL_FLOAT, GL_FALSE, sizeof(float) * 5, lineAsTriangleVertices.data()); + glVertexAttribPointer(CelestiaGLProgram::NextVCoordAttributeIndex, + 2, GL_FLOAT, GL_FALSE, sizeof(float) * 5, lineAsTriangleVertices.data() + 2); + glVertexAttribPointer(CelestiaGLProgram::ScaleFactorAttributeIndex, + 1, GL_FLOAT, GL_FALSE, sizeof(float) * 5, lineAsTriangleVertices.data() + 4); + } if (r.tex != nullptr) { glEnableVertexAttribArray(CelestiaGLProgram::TextureCoord0AttributeIndex); @@ -5482,22 +5542,22 @@ void Renderer::drawRectangle(const Rect &r, int fishEyeOverrideMode, const Eigen prog->use(); prog->setMVPMatrices(p, m); - if (r.type != Rect::Type::BorderOnly) + if (solid) { glDrawArrays(GL_TRIANGLE_FAN, 0, 4); } else { - if (r.lw != 1.0f) - glLineWidth(r.lw * screenDpi / 96.0f); - glDrawArrays(GL_LINE_LOOP, 0, 4); - if (r.lw != 1.0f) - glLineWidth(1.0f * screenDpi / 96.0f); + prog->lineWidthX = getLineWidthX() * r.lw; + prog->lineWidthY = getLineWidthY() * r.lw; + glDrawElements(GL_TRIANGLES, lineAsTriangleIndcies.size(), GL_UNSIGNED_SHORT, lineAsTriangleIndcies.data()); } glDisableVertexAttribArray(CelestiaGLProgram::ColorAttributeIndex); glDisableVertexAttribArray(CelestiaGLProgram::TextureCoord0AttributeIndex); glDisableVertexAttribArray(CelestiaGLProgram::VertexCoordAttributeIndex); + glDisableVertexAttribArray(CelestiaGLProgram::NextVCoordAttributeIndex); + glDisableVertexAttribArray(CelestiaGLProgram::ScaleFactorAttributeIndex); } void Renderer::setRenderRegion(int x, int y, int width, int height, bool withScissor) @@ -5551,13 +5611,18 @@ bool Renderer::getInfo(map& info) const #endif GLint pointSizeRange[2]; + GLfloat lineWidthRange[2]; #ifdef GL_ES glGetIntegerv(GL_ALIASED_POINT_SIZE_RANGE, pointSizeRange); + glGetFloatv(GL_ALIASED_LINE_WIDTH_RANGE, lineWidthRange); #else glGetIntegerv(GL_SMOOTH_POINT_SIZE_RANGE, pointSizeRange); + glGetFloatv(GL_SMOOTH_LINE_WIDTH_RANGE, lineWidthRange); #endif info["PointSizeMin"] = to_string(pointSizeRange[0]); info["PointSizeMax"] = to_string(pointSizeRange[1]); + info["LineWidthMin"] = to_string(lineWidthRange[0]); + info["LineWidthMax"] = to_string(lineWidthRange[1]); #ifndef GL_ES GLfloat pointSizeGran = 0; @@ -6142,8 +6207,6 @@ Renderer::renderSolarSystemObjects(const Observer &observer, #else setBlendingFactors(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); #endif - enableSmoothLines(); - // Scan through the list of orbits and render any that overlap this interval for (const auto& orbit : orbitPathList) { @@ -6163,8 +6226,6 @@ Renderer::renderSolarSystemObjects(const Observer &observer, m); } } - - disableSmoothLines(); } // Render transparent objects in the second pass @@ -6178,13 +6239,11 @@ Renderer::renderSolarSystemObjects(const Observer &observer, } // Render annotations in this interval - enableSmoothLines(); annotation = renderSortedAnnotations(annotation, nearPlaneDistance, farPlaneDistance, FontNormal); endObjectAnnotations(); - disableSmoothLines(); } // reset the depth range diff --git a/src/celengine/render.h b/src/celengine/render.h index 3b85fa9ad..f33dca19e 100644 --- a/src/celengine/render.h +++ b/src/celengine/render.h @@ -48,6 +48,21 @@ struct Matrices const Eigen::Matrix4f *modelview; }; +struct LineStripEnd +{ + LineStripEnd(Eigen::Vector3f point, float scale) : point(point), scale(scale) {}; + Eigen::Vector3f point; + float scale; +}; + +struct LineEnds +{ + LineEnds(Eigen::Vector3f point1, Eigen::Vector3f point2, float scale) : point1(point1), point2(point2), scale(scale) {}; + Eigen::Vector3f point1; + Eigen::Vector3f point2; + float scale; +}; + struct LightSource { Eigen::Vector3d position; @@ -73,7 +88,10 @@ enum class VOType Rectangle = 2, Terminator = 3, LargeStar = 4, - Count = 5 + AxisLetter = 5, + MarkerLine = 6, + Ecliptic = 7, + Count = 8, }; enum class RenderMode @@ -257,6 +275,12 @@ class Renderer int getWindowWidth() const; int getWindowHeight() const; + float getScaleFactor() const; + float getPointWidth() const; + float getPointHeight() const; + float getLineWidthX() const; + float getLineWidthY() const; + // GL wrappers void getViewport(int* x, int* y, int* w, int* h) const; void getViewport(std::array& viewport) const; @@ -279,6 +303,9 @@ class Renderer void enableDepthTest() noexcept; void disableDepthTest() noexcept; + void enableSmoothLines(); + void disableSmoothLines(); + void drawRectangle(const Rect& r, int fishEyeOverrideMode, const Eigen::Matrix4f& p, const Eigen::Matrix4f& m = Eigen::Matrix4f::Identity()); void setRenderRegion(int x, int y, int width, int height, bool withScissor = true); @@ -718,9 +745,6 @@ class Renderer void createShadowFBO(); - void enableSmoothLines(); - void disableSmoothLines(); - #ifdef USE_HDR private: int sceneTexWidth, sceneTexHeight; diff --git a/src/celengine/shadermanager.cpp b/src/celengine/shadermanager.cpp index f2e6f43f1..87d15d06f 100644 --- a/src/celengine/shadermanager.cpp +++ b/src/celengine/shadermanager.cpp @@ -74,7 +74,7 @@ invariant gl_Position; static const char *VPFunction = "#ifdef FISHEYE\n" - "void set_vp(vec4 in_Position) {\n" + "vec4 calc_vp(vec4 in_Position) {\n" " float PID2 = 1.570796326794896619231322;\n" " vec4 inPos = ModelViewMatrix * in_Position;\n" " float l = length(inPos.xy);\n" @@ -83,17 +83,38 @@ static const char *VPFunction = " float lensR = phi / PID2;\n" " inPos.xy *= (lensR / l);\n" " }\n" - " gl_Position = ProjectionMatrix * inPos;\n" + " return ProjectionMatrix * inPos;\n" "}\n" "#else\n" - "void set_vp(vec4 in_Position) {\n" - " gl_Position = MVPMatrix * in_Position;\n" + "vec4 calc_vp(vec4 in_Position) {\n" + " return MVPMatrix * in_Position;\n" "}\n" - "#endif\n"; + "#endif\n" + "void set_vp(vec4 in_Position) {\n" + " gl_Position = calc_vp(in_Position);\n" + "}\n"; -static const char* VertexPosition = +static const char* NormalVertexPosition = "set_vp(in_Position);\n"; +static const char* LineVertexPosition = + "vec4 thisPos = calc_vp(in_Position);\n" + "vec4 nextPos = calc_vp(in_PositionNext);\n" + "float w = thisPos.w;\n" + "thisPos /= w;\n" + "nextPos /= nextPos.w;\n" + "vec2 transform = normalize(nextPos.xy - thisPos.xy);\n" + "transform = vec2(transform.y * lineWidthX, -transform.x * lineWidthY) * in_ScaleFactor;\n" + "gl_Position = thisPos;\n" + "gl_Position.xy += transform;\n" + "gl_Position *= w;\n"; + + +static string VertexPosition(const ShaderProperties& props) +{ + return (props.texUsage & ShaderProperties::LineAsTriangles) ? LineVertexPosition : NormalVertexPosition; +} + static const char* FragmentHeader = ""; static const char* CommonAttribs = R"glsl( @@ -1689,6 +1710,17 @@ StaticPointSize() return source; } +static string +LineDeclaration() +{ + string source; + source += DeclareAttribute("in_PositionNext", Shader_Vector4); + source += DeclareAttribute("in_ScaleFactor", Shader_Float); + source += DeclareUniform("lineWidthX", Shader_Float); + source += DeclareUniform("lineWidthY", Shader_Float); + return source; +} + static string CalculateShadow() { @@ -1854,6 +1886,9 @@ ShaderManager::buildVertexShader(const ShaderProperties& props) if (props.hasShadowMap()) source += "uniform mat4 ShadowMatrix0;\n"; + if (props.texUsage & ShaderProperties::LineAsTriangles) + source += LineDeclaration(); + if (props.fishEyeOverride != ShaderProperties::FisheyeOverrideModeDisabled && fisheyeEnabled) source += "#define FISHEYE\n"; @@ -2076,7 +2111,7 @@ ShaderManager::buildVertexShader(const ShaderProperties& props) if (props.hasShadowMap()) source += "shadowTexCoord0 = ShadowMatrix0 * vec4(in_Position.xyz, 1.0);\n"; - source += VertexPosition; + source += VertexPosition(props); source += "}\n"; DumpVSSource(source); @@ -2699,6 +2734,9 @@ ShaderManager::buildRingsVertexShader(const ShaderProperties& props) if (props.texUsage & ShaderProperties::DiffuseTexture) source += "varying vec2 diffTexCoord;\n"; + if (props.texUsage & ShaderProperties::LineAsTriangles) + source += LineDeclaration(); + if (props.fishEyeOverride != ShaderProperties::FisheyeOverrideModeDisabled && fisheyeEnabled) source += "#define FISHEYE\n"; @@ -2719,7 +2757,7 @@ ShaderManager::buildRingsVertexShader(const ShaderProperties& props) } } - source += VertexPosition; + source += VertexPosition(props); source += "}\n"; DumpVSSource(source); @@ -2858,6 +2896,9 @@ ShaderManager::buildAtmosphereVertexShader(const ShaderProperties& props) source += "varying vec3 scatterEx;\n"; source += "varying vec3 eyeDir_obj;\n"; + if (props.texUsage & ShaderProperties::LineAsTriangles) + source += LineDeclaration(); + if (props.fishEyeOverride != ShaderProperties::FisheyeOverrideModeDisabled && fisheyeEnabled) source += "#define FISHEYE\n"; @@ -2872,7 +2913,7 @@ ShaderManager::buildAtmosphereVertexShader(const ShaderProperties& props) source += AtmosphericEffects(props); source += "eyeDir_obj = eyeDir;\n"; - source += VertexPosition; + source += VertexPosition(props); source += "}\n"; DumpVSSource(source); @@ -2967,6 +3008,9 @@ ShaderManager::buildEmissiveVertexShader(const ShaderProperties& props) source += DeclareVarying("v_Color", Shader_Vector4); source += DeclareVarying("v_TexCoord0", Shader_Vector2); + if (props.texUsage & ShaderProperties::LineAsTriangles) + source += LineDeclaration(); + if (props.fishEyeOverride != ShaderProperties::FisheyeOverrideModeDisabled && fisheyeEnabled) source += "#define FISHEYE\n"; @@ -2998,7 +3042,7 @@ ShaderManager::buildEmissiveVertexShader(const ShaderProperties& props) else if (props.texUsage & ShaderProperties::StaticPointSize) source += StaticPointSize(); - source += VertexPosition; + source += VertexPosition(props); source += "}\n"; // End of main() @@ -3095,6 +3139,9 @@ ShaderManager::buildParticleVertexShader(const ShaderProperties& props) source << "varying vec3 position_obj;\n"; } + if (props.texUsage & ShaderProperties::LineAsTriangles) + source << LineDeclaration(); + if (props.fishEyeOverride != ShaderProperties::FisheyeOverrideModeDisabled && fisheyeEnabled) source << "#define FISHEYE\n"; @@ -3132,7 +3179,7 @@ ShaderManager::buildParticleVertexShader(const ShaderProperties& props) else if (props.texUsage & ShaderProperties::StaticPointSize) source << StaticPointSize(); - source << VertexPosition; + source << VertexPosition(props); source << "}\n"; // End of main() @@ -3283,6 +3330,17 @@ ShaderManager::buildProgram(const ShaderProperties& props) CelestiaGLProgram::IntensityAttributeIndex, "in_Intensity"); + if (props.texUsage & ShaderProperties::LineAsTriangles) + { + glBindAttribLocation(prog->getID(), + CelestiaGLProgram::NextVCoordAttributeIndex, + "in_PositionNext"); + + glBindAttribLocation(prog->getID(), + CelestiaGLProgram::ScaleFactorAttributeIndex, + "in_ScaleFactor"); + } + if (props.texUsage & ShaderProperties::NormalTexture) { glBindAttribLocation(prog->getID(), @@ -3593,6 +3651,12 @@ CelestiaGLProgram::initParameters() { pointScale = floatParam("pointScale"); } + + if (props.texUsage & ShaderProperties::LineAsTriangles) + { + lineWidthX = floatParam("lineWidthX"); + lineWidthY = floatParam("lineWidthY"); + } } diff --git a/src/celengine/shadermanager.h b/src/celengine/shadermanager.h index 637a455e4..64d97c750 100644 --- a/src/celengine/shadermanager.h +++ b/src/celengine/shadermanager.h @@ -67,6 +67,7 @@ class ShaderProperties PointSprite = 0x4000, SharedTextureCoords = 0x8000, StaticPointSize = 0x10000, + LineAsTriangles = 0x20000, }; enum @@ -194,6 +195,8 @@ class CelestiaGLProgram PointSizeAttributeIndex = 7, ColorAttributeIndex = 8, IntensityAttributeIndex = 9, + NextVCoordAttributeIndex = 10, + ScaleFactorAttributeIndex = 11, }; public: @@ -260,6 +263,10 @@ class CelestiaGLProgram // Scale factor for point sprites FloatShaderParameter pointScale; + // Used to draw line as triangles + FloatShaderParameter lineWidthX; + FloatShaderParameter lineWidthY; + // Color sent as a uniform Vec4ShaderParameter color; diff --git a/src/celengine/skygrid.cpp b/src/celengine/skygrid.cpp index 5af266898..62d261196 100644 --- a/src/celengine/skygrid.cpp +++ b/src/celengine/skygrid.cpp @@ -392,7 +392,7 @@ SkyGrid::render(Renderer& renderer, int windowHeight) { ShaderProperties shadprop; - shadprop.texUsage = ShaderProperties::VertexColors; + shadprop.texUsage = ShaderProperties::VertexColors | ShaderProperties::LineAsTriangles; shadprop.lightModel = ShaderProperties::UnlitModel; auto *prog = renderer.getShaderManager().getShader(shadprop); if (prog == nullptr) @@ -556,14 +556,23 @@ SkyGrid::render(Renderer& renderer, vecgl::rotate((xrot90 * m_orientation.conjugate() * xrot90.conjugate()).cast()) * vecgl::scale(1000.0f); prog->setMVPMatrices(renderer.getProjectionMatrix(), m); + prog->lineWidthX = renderer.getLineWidthX(); + prog->lineWidthY = renderer.getLineWidthY(); double arcStep = (maxTheta - minTheta) / (double) ARC_SUBDIVISIONS; double theta0 = minTheta; - auto buffer = new Vector3f[ARC_SUBDIVISIONS+1]; + vector buffer; + buffer.reserve(2 * (ARC_SUBDIVISIONS + 2)); glEnableVertexAttribArray(CelestiaGLProgram::VertexCoordAttributeIndex); + glEnableVertexAttribArray(CelestiaGLProgram::NextVCoordAttributeIndex); + glEnableVertexAttribArray(CelestiaGLProgram::ScaleFactorAttributeIndex); glVertexAttribPointer(CelestiaGLProgram::VertexCoordAttributeIndex, - 3, GL_FLOAT, GL_FALSE, 0, buffer); + 3, GL_FLOAT, GL_FALSE, sizeof(LineStripEnd), &buffer[0].point); + glVertexAttribPointer(CelestiaGLProgram::NextVCoordAttributeIndex, + 3, GL_FLOAT, GL_FALSE, sizeof(LineStripEnd), &buffer[2].point); + glVertexAttribPointer(CelestiaGLProgram::ScaleFactorAttributeIndex, + 1, GL_FLOAT, GL_FALSE, sizeof(LineStripEnd), &buffer[0].scale); for (int dec = startDec; dec <= endDec; dec += decIncrement) { @@ -571,15 +580,17 @@ SkyGrid::render(Renderer& renderer, double cosPhi = cos(phi); double sinPhi = sin(phi); - for (int j = 0; j <= ARC_SUBDIVISIONS; j++) + for (int j = 0; j <= ARC_SUBDIVISIONS + 1; j++) { double theta = theta0 + j * arcStep; auto x = (float) (cosPhi * std::cos(theta)); auto y = (float) (cosPhi * std::sin(theta)); auto z = (float) sinPhi; - buffer[j] = {x, z, -y}; // convert to Celestia coords + Vector3f position = {x, z, -y}; // convert to Celestia coords + buffer[2 * j] = {position, -0.5f}; + buffer[2 * j + 1] = {position, 0.5f}; } - glDrawArrays(GL_LINE_STRIP, 0, ARC_SUBDIVISIONS+1); + glDrawArrays(GL_TRIANGLE_STRIP, 0, 2 * (ARC_SUBDIVISIONS + 1)); // Place labels at the intersections of the view frustum planes // and the parallels. @@ -646,15 +657,17 @@ SkyGrid::render(Renderer& renderer, double cosTheta = cos(theta); double sinTheta = sin(theta); - for (int j = 0; j <= ARC_SUBDIVISIONS; j++) + for (int j = 0; j <= ARC_SUBDIVISIONS + 1; j++) { double phi = phi0 + j * arcStep; auto x = (float) (cos(phi) * cosTheta); auto y = (float) (cos(phi) * sinTheta); auto z = (float) sin(phi); - buffer[j] = {x, z, -y}; // convert to Celestia coords + Vector3f position = {x, z, -y}; // convert to Celestia coords + buffer[2 * j] = {position, -0.5f}; + buffer[2 * j + 1] = {position, 0.5f}; } - glDrawArrays(GL_LINE_STRIP, 0, ARC_SUBDIVISIONS+1); + glDrawArrays(GL_TRIANGLE_STRIP, 0, 2 * (ARC_SUBDIVISIONS + 1)); // Place labels at the intersections of the view frustum planes // and the meridians. @@ -704,16 +717,47 @@ SkyGrid::render(Renderer& renderer, } // Draw crosses indicating the north and south poles - buffer[0] = {-polarCrossSize, 1.0f, 0.0f}; - buffer[1] = { polarCrossSize, 1.0f, 0.0f}; - buffer[2] = {0.0f, 1.0f, -polarCrossSize}; - buffer[3] = {0.0f, 1.0f, polarCrossSize}; - buffer[4] = {-polarCrossSize, -1.0f, 0.0f}; - buffer[5] = { polarCrossSize, -1.0f, 0.0f}; - buffer[6] = {0.0f, -1.0f, -polarCrossSize}; - buffer[7] = {0.0f, -1.0f, polarCrossSize}; - glDrawArrays(GL_LINES, 0, 8); + array lineAsTriangleVertices = { + -polarCrossSize, 1.0f, 0.0f, polarCrossSize, 1.0f, 0.0f, -0.5, + -polarCrossSize, 1.0f, 0.0f, polarCrossSize, 1.0f, 0.0f, 0.5, + + polarCrossSize, 1.0f, 0.0f, -polarCrossSize, 1.0f, 0.0f, -0.5, + polarCrossSize, 1.0f, 0.0f, -polarCrossSize, 1.0f, 0.0f, 0.5, + + 0.0f, 1.0f, -polarCrossSize, 0.0f, 1.0f, polarCrossSize, -0.5, + 0.0f, 1.0f, -polarCrossSize, 0.0f, 1.0f, polarCrossSize, 0.5, + + 0.0f, 1.0f, polarCrossSize, 0.0f, 1.0f, -polarCrossSize, -0.5, + 0.0f, 1.0f, polarCrossSize, 0.0f, 1.0f, -polarCrossSize, 0.5, + + -polarCrossSize, -1.0f, 0.0f, polarCrossSize, -1.0f, 0.0f, -0.5, + -polarCrossSize, -1.0f, 0.0f, polarCrossSize, -1.0f, 0.0f, 0.5, + + polarCrossSize, -1.0f, 0.0f, -polarCrossSize, -1.0f, 0.0f, -0.5, + polarCrossSize, -1.0f, 0.0f, -polarCrossSize, -1.0f, 0.0f, 0.5, + + 0.0f, -1.0f, -polarCrossSize, 0.0f, -1.0f, polarCrossSize, -0.5, + 0.0f, -1.0f, -polarCrossSize, 0.0f, -1.0f, polarCrossSize, 0.5, + + 0.0f, -1.0f, polarCrossSize, 0.0f, -1.0f, -polarCrossSize, -0.5, + 0.0f, -1.0f, polarCrossSize, 0.0f, -1.0f, -polarCrossSize, 0.5, + }; + constexpr array lineAsTriangleIndcies = { + 0, 1, 2, 2, 3, 0, + 4, 5, 6, 6, 7, 4, + 8, 9, 10, 10, 11, 8, + 12, 13, 14, 14, 15, 12 + }; + + glVertexAttribPointer(CelestiaGLProgram::VertexCoordAttributeIndex, + 3, GL_FLOAT, GL_FALSE, sizeof(float) * 7, lineAsTriangleVertices.data()); + glVertexAttribPointer(CelestiaGLProgram::NextVCoordAttributeIndex, + 3, GL_FLOAT, GL_FALSE, sizeof(float) * 7, lineAsTriangleVertices.data() + 3); + glVertexAttribPointer(CelestiaGLProgram::ScaleFactorAttributeIndex, + 1, GL_FLOAT, GL_FALSE, sizeof(float) * 7, lineAsTriangleVertices.data() + 6); + glDrawElements(GL_TRIANGLES, lineAsTriangleIndcies.size(), GL_UNSIGNED_SHORT, lineAsTriangleIndcies.data()); glDisableVertexAttribArray(CelestiaGLProgram::VertexCoordAttributeIndex); - delete[] buffer; + glDisableVertexAttribArray(CelestiaGLProgram::NextVCoordAttributeIndex); + glDisableVertexAttribArray(CelestiaGLProgram::ScaleFactorAttributeIndex); } diff --git a/src/celengine/visibleregion.cpp b/src/celengine/visibleregion.cpp index 678464a66..74b41355e 100644 --- a/src/celengine/visibleregion.cpp +++ b/src/celengine/visibleregion.cpp @@ -84,7 +84,7 @@ constexpr const unsigned maxSections = 360; static void renderTerminator(Renderer* renderer, - const vector& pos, + const vector& pos, const Color& color, const Matrices& mvp) { @@ -94,8 +94,9 @@ renderTerminator(Renderer* renderer, * Because of this we make calculations on a CPU and stream results to GPU. */ + float lineWidth = renderer->getScreenDpi() / 96.0f; ShaderProperties shadprop; - shadprop.texUsage = ShaderProperties::VertexColors; + shadprop.texUsage = ShaderProperties::VertexColors | ShaderProperties::LineAsTriangles; shadprop.lightModel = ShaderProperties::UnlitModel; auto *prog = renderer->getShaderManager().getShader(shadprop); if (prog == nullptr) @@ -106,18 +107,26 @@ renderTerminator(Renderer* renderer, vo.bindWritable(); if (!vo.initialized()) { - vo.setBufferSize(maxSections * sizeof(Vector3f)); + vo.setBufferSize((maxSections + 2) * 2 * sizeof(LineStripEnd)); vo.allocate(); - vo.setVertices(3, GL_FLOAT); + vo.setVertices(3, GL_FLOAT, false, sizeof(LineStripEnd), 0); + vo.setVertexAttribArray(CelestiaGLProgram::NextVCoordAttributeIndex, + 3, GL_FLOAT, false, sizeof(LineStripEnd) + , 2 * sizeof(LineStripEnd) + offsetof(LineStripEnd, point)); + vo.setVertexAttribArray(CelestiaGLProgram::ScaleFactorAttributeIndex, + 1, GL_FLOAT, false, sizeof(LineStripEnd) + , offsetof(LineStripEnd, scale)); } - vo.setBufferData(pos.data(), 0, pos.size() * sizeof(Vector3f)); + vo.setBufferData(pos.data(), 0, pos.size() * sizeof(LineStripEnd)); prog->use(); + prog->lineWidthX = renderer->getLineWidthX(); + prog->lineWidthY = renderer->getLineWidthY(); prog->setMVPMatrices(*mvp.projection, *mvp.modelview); glVertexAttrib(CelestiaGLProgram::ColorAttributeIndex, color); - vo.draw(GL_LINE_LOOP, pos.size()); + vo.draw(GL_TRIANGLE_STRIP, pos.size() - 2); vo.unbind(); } @@ -198,17 +207,19 @@ VisibleRegion::render(Renderer* renderer, Vector3d e_ = e.cwiseProduct(recipSemiAxes); double ee = e_.squaredNorm(); - vector pos; - pos.reserve(nSections); + vector pos; + pos.reserve((nSections + 2) * 2); - for (unsigned i = 0; i < nSections; i++) + for (unsigned i = 0; i <= nSections + 1; i++) { double theta = (double) i / (double) (nSections) * 2.0 * PI; Vector3d w = cos(theta) * uAxis + sin(theta) * vAxis; Vector3d toCenter = ellipsoidTangent(recipSemiAxes, w, e, e_, ee); toCenter *= maxSemiAxis * scale; - pos.push_back(toCenter.cast()); + Vector3f thisPoint = toCenter.cast(); + pos.emplace_back(thisPoint, -0.5); + pos.emplace_back(thisPoint, 0.5); } Affine3f transform = Translation3f(position) * qf.conjugate();