Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 5 additions & 3 deletions src/display/Characters.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,8 @@ void CharacterBatch::CharFakeGL::drawPathSegment(const glm::vec3 &p1,
const glm::vec3 &p2,
const Color color)
{
mmgl::generateLineQuadsSafe(m_pathLineQuads, p1, p2, PATH_LINE_WIDTH, color);
m_pathLines.emplace_back(color, p1);
m_pathLines.emplace_back(color, p2);
}

void CharacterBatch::drawPreSpammedPath(const Coordinate &c1,
Expand Down Expand Up @@ -359,8 +360,9 @@ void CharacterBatch::CharFakeGL::reallyDrawPaths(OpenGL &gl)
= GLRenderState().withDepthFunction(std::nullopt).withBlend(BlendModeEnum::TRANSPARENCY);

gl.renderPoints(m_pathPoints, blended_noDepth.withPointSize(PATH_POINT_SIZE));
if (!m_pathLineQuads.empty()) {
gl.renderColoredQuads(m_pathLineQuads, blended_noDepth);
if (!m_pathLines.empty()) {
gl.renderColoredLines(m_pathLines,
blended_noDepth.withLineParams(LineParams{PATH_LINE_WIDTH}));
}
}

Expand Down
2 changes: 1 addition & 1 deletion src/display/Characters.h
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@ class NODISCARD CharacterBatch final
std::vector<ColorVert> m_charLines;
std::vector<ColoredTexVert> m_charRoomQuads;
std::vector<ColorVert> m_pathPoints;
std::vector<ColorVert> m_pathLineQuads;
std::vector<ColorVert> m_pathLines;
std::vector<FontVert3d> m_screenSpaceArrows;
std::vector<GLText> m_names;
std::map<Coordinate, int, CoordCompare> m_coordCounts;
Expand Down
8 changes: 7 additions & 1 deletion src/display/Infomarks.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,8 @@ void InfomarksBatch::drawLine(const glm::vec3 &a, const glm::vec3 &b)
const glm::vec3 start_v = a + m_offset;
const glm::vec3 end_v = b + m_offset;

mmgl::generateLineQuadsSafe(m_quads, start_v, end_v, INFOMARK_ARROW_LINE_WIDTH, m_color);
m_lines.emplace_back(m_color, start_v);
m_lines.emplace_back(m_color, end_v);
}

void InfomarksBatch::drawTriangle(const glm::vec3 &a, const glm::vec3 &b, const glm::vec3 &c)
Expand Down Expand Up @@ -172,6 +173,7 @@ InfomarksMeshes InfomarksBatch::getMeshes()
auto &gl = m_realGL;
result.points = gl.createPointBatch(m_points);
result.tris = gl.createColoredTriBatch(m_tris);
result.lines = gl.createColoredLineBatch(m_lines);
result.quads = gl.createColoredQuadBatch(m_quads);

{
Expand All @@ -193,6 +195,9 @@ void InfomarksBatch::renderImmediate(const GLRenderState &state)
if (!m_tris.empty()) {
gl.renderColoredTris(m_tris, state);
}
if (!m_lines.empty()) {
gl.renderColoredLines(m_lines, state.withLineParams(LineParams{INFOMARK_ARROW_LINE_WIDTH}));
}
if (!m_quads.empty()) {
gl.renderColoredQuads(m_quads, state);
}
Expand All @@ -215,6 +220,7 @@ void InfomarksMeshes::render()

points.render(common_state.withPointSize(INFOMARK_POINT_SIZE));
tris.render(common_state);
lines.render(common_state.withLineParams(LineParams{INFOMARK_ARROW_LINE_WIDTH}));
quads.render(common_state);
textMesh.render(common_state);
}
Expand Down
2 changes: 2 additions & 0 deletions src/display/Infomarks.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ struct NODISCARD InfomarksMeshes final
{
UniqueMesh points;
UniqueMesh tris;
UniqueMesh lines;
UniqueMesh quads;
UniqueMesh textMesh;
bool isValid = false;
Expand All @@ -41,6 +42,7 @@ struct NODISCARD InfomarksBatch final

std::vector<ColorVert> m_points;
std::vector<ColorVert> m_tris;
std::vector<ColorVert> m_lines;
std::vector<ColorVert> m_quads;

// REVISIT: This is ill-advised and may contain bugs.
Expand Down
20 changes: 20 additions & 0 deletions src/resources/shaders/legacy/line/acolor/frag.glsl
Original file line number Diff line number Diff line change
@@ -1,10 +1,30 @@
uniform vec4 uColor;

in vec4 vColor;
in vec2 vUv;
in float vLineLength;
in float vWidth;

out vec4 vFragmentColor;

void main()
{
float halfWidth = vWidth * 0.5;

// Calculate distance to the segment
float dx = max(-vUv.x, 0.0) + max(vUv.x - vLineLength, 0.0);
float dy = vUv.y;
float dist = sqrt(dx * dx + dy * dy);

// Anti-aliasing
// Smoothstep creates a nice alpha ramp over 1 pixel
float feather = 1.0;
float alpha = 1.0 - smoothstep(halfWidth - feather, halfWidth + feather, dist);

if (alpha <= 0.0) {
discard;
}

vFragmentColor = vColor * uColor;
vFragmentColor.a *= alpha;
}
39 changes: 34 additions & 5 deletions src/resources/shaders/legacy/line/acolor/vert.glsl
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@ layout(location = 1) in vec3 aVert1;
layout(location = 2) in vec3 aVert2;

out vec4 vColor;
out vec2 vUv;
out float vLineLength;
out float vWidth;
Comment on lines +11 to +12

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

suggestion (performance): Consider marking vLineLength and vWidth as flat to avoid unnecessary interpolation and potential precision issues.

These values are per-line, not per-vertex, so they should be declared as flat out float in the vertex shader and flat in float in the fragment shader to reflect their per-primitive nature rather than being interpolated per-fragment.

Suggested implementation:

out vec4 vColor;
out vec2 vUv;
flat out float vLineLength;
flat out float vWidth;

In the matching fragment shader for this pipeline (likely something like src/resources/shaders/legacy/line/acolor/frag.glsl), update the corresponding varyings to:

  • Replace in float vLineLength; with flat in float vLineLength;
  • Replace in float vWidth; with flat in float vWidth;

This will ensure the per-line values are not interpolated per-fragment and avoids GLSL interface mismatch between vertex and fragment shaders.


void main()
{
Expand All @@ -15,9 +18,11 @@ void main()
vec4 clip1 = uMVP * vec4(aVert1, 1.0);
vec4 clip2 = uMVP * vec4(aVert2, 1.0);

// Standard perspective divide
vec2 ndc1 = clip1.xy / clip1.w;
vec2 ndc2 = clip2.xy / clip2.w;

// Screen coordinates
vec2 screen1 = (ndc1 + 1.0) * 0.5 * vec2(uViewport.zw);
vec2 screen2 = (ndc2 + 1.0) * 0.5 * vec2(uViewport.zw);

Expand All @@ -30,14 +35,38 @@ void main()
}
vec2 normal = vec2(-dir.y, dir.x);

vec2 offset = normal * uLineWidth * 0.5;
// Padding for anti-aliasing (e.g. 1 pixel)
float feather = 1.0;
float halfWidth = uLineWidth * 0.5;
float totalHalfWidth = halfWidth + feather;

vLineLength = len;
vWidth = uLineWidth;

vec2 pos;
float z;
if (gl_VertexID == 0) { pos = screen1 + offset; z = clip1.z / clip1.w; }
else if (gl_VertexID == 1) { pos = screen1 - offset; z = clip1.z / clip1.w; }
else if (gl_VertexID == 2) { pos = screen2 - offset; z = clip2.z / clip2.w; }
else { pos = screen2 + offset; z = clip2.z / clip2.w; }

// Expand longitudinally to allow for round caps
vec2 offsetL = dir * totalHalfWidth;
vec2 offsetP = normal * totalHalfWidth;

if (gl_VertexID == 0) {
pos = screen1 - offsetL + offsetP;
z = clip1.z / clip1.w;
vUv = vec2(-totalHalfWidth, totalHalfWidth);
} else if (gl_VertexID == 1) {
pos = screen1 - offsetL - offsetP;
z = clip1.z / clip1.w;
vUv = vec2(-totalHalfWidth, -totalHalfWidth);
} else if (gl_VertexID == 2) {
pos = screen2 + offsetL - offsetP;
z = clip2.z / clip2.w;
vUv = vec2(len + totalHalfWidth, -totalHalfWidth);
} else { // gl_VertexID == 3
pos = screen2 + offsetL + offsetP;
z = clip2.z / clip2.w;
vUv = vec2(len + totalHalfWidth, totalHalfWidth);
}

vec2 final_ndc = (pos / vec2(uViewport.zw)) * 2.0 - 1.0;
gl_Position = vec4(final_ndc, z, 1.0);
Expand Down
18 changes: 18 additions & 0 deletions src/resources/shaders/legacy/line/ucolor/frag.glsl
Original file line number Diff line number Diff line change
@@ -1,8 +1,26 @@
uniform vec4 uColor;

in vec2 vUv;
in float vLineLength;
in float vWidth;

out vec4 vFragmentColor;

void main()
{
float halfWidth = vWidth * 0.5;

float dx = max(-vUv.x, 0.0) + max(vUv.x - vLineLength, 0.0);
float dy = vUv.y;
float dist = sqrt(dx * dx + dy * dy);

float feather = 1.0;
float alpha = 1.0 - smoothstep(halfWidth - feather, halfWidth + feather, dist);

if (alpha <= 0.0) {
discard;
}

vFragmentColor = uColor;
vFragmentColor.a *= alpha;
}
36 changes: 31 additions & 5 deletions src/resources/shaders/legacy/line/ucolor/vert.glsl
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,10 @@ uniform ivec4 uViewport; // x, y, width, height
layout(location = 0) in vec3 aVert1;
layout(location = 1) in vec3 aVert2;

out vec2 vUv;
out float vLineLength;
out float vWidth;

void main()
{
vec4 clip1 = uMVP * vec4(aVert1, 1.0);
Expand All @@ -25,14 +29,36 @@ void main()
}
vec2 normal = vec2(-dir.y, dir.x);

vec2 offset = normal * uLineWidth * 0.5;
float feather = 1.0;
float halfWidth = uLineWidth * 0.5;
float totalHalfWidth = halfWidth + feather;
Comment on lines +32 to +34

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

suggestion: The hardcoded feather value is duplicated and could drift from the fragment shader; consider sharing it via a uniform or constant.

feather = 1.0 is set both here and in the fragment shader. If only one is updated later, the geometry expansion and alpha falloff will diverge. Please use a shared uniform or common constant/define so feather stays consistent and AA tuning is centralized.

Suggested implementation:

uniform mat4 uMVP;
uniform float uFeather;

    // Anti-aliasing
    // Smoothstep creates a nice alpha ramp over 1 pixel
    float feather = uFeather;
    float alpha = 1.0 - smoothstep(halfWidth - feather, halfWidth + feather, dist);

To fully centralize and share the feather parameter:

  1. In the corresponding fragment shader (likely src/resources/shaders/legacy/line/ucolor/frag.glsl), declare uniform float uFeather; and replace any float feather = 1.0; with float feather = uFeather;.
  2. In the rendering code that binds this shader, set the uFeather uniform once (e.g., via glUniform1f) so both vertex and fragment shaders receive the same value.
  3. Optionally, define uFeather in a common include GLSL file if your shader system supports shared includes, so future line shaders can reuse the same AA parameter.


vLineLength = len;
vWidth = uLineWidth;

vec2 pos;
float z;
if (gl_VertexID == 0) { pos = screen1 + offset; z = clip1.z / clip1.w; }
else if (gl_VertexID == 1) { pos = screen1 - offset; z = clip1.z / clip1.w; }
else if (gl_VertexID == 2) { pos = screen2 - offset; z = clip2.z / clip2.w; }
else { pos = screen2 + offset; z = clip2.z / clip2.w; }

vec2 offsetL = dir * totalHalfWidth;
vec2 offsetP = normal * totalHalfWidth;

if (gl_VertexID == 0) {
pos = screen1 - offsetL + offsetP;
z = clip1.z / clip1.w;
vUv = vec2(-totalHalfWidth, totalHalfWidth);
} else if (gl_VertexID == 1) {
pos = screen1 - offsetL - offsetP;
z = clip1.z / clip1.w;
vUv = vec2(-totalHalfWidth, -totalHalfWidth);
} else if (gl_VertexID == 2) {
pos = screen2 + offsetL - offsetP;
z = clip2.z / clip2.w;
vUv = vec2(len + totalHalfWidth, -totalHalfWidth);
} else {
pos = screen2 + offsetL + offsetP;
z = clip2.z / clip2.w;
vUv = vec2(len + totalHalfWidth, totalHalfWidth);
}

vec2 final_ndc = (pos / vec2(uViewport.zw)) * 2.0 - 1.0;
gl_Position = vec4(final_ndc, z, 1.0);
Expand Down
Loading