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
3 changes: 3 additions & 0 deletions .github/workflows/continuous-integration-workflow.yml
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,9 @@ jobs:
- name: Run text visual suite
run: xvfb-run -a ctest --test-dir cmake_build_dir_rt \
-L visual-text --output-on-failure -VV
- name: Run DrawList raster visual tests
run: xvfb-run -a ctest --test-dir cmake_build_dir_rt \
-L visual-raster --output-on-failure -VV
- name: Upload artifacts
uses: actions/upload-artifact@v7
with:
Expand Down
42 changes: 42 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -965,6 +965,8 @@ if(COIN_BUILD_VISUAL_TESTS)
"unlit_cube_basic,unlit_transformed_cubes,unlit_vertex_colors,unlit_orthographic_basic,unlit_depth_overlap")
set(COIN_MATERIAL_VISUAL_SPECS
"cube_basic,camera_persp_basic,camera_ortho_basic,material_emissive,two_lights,point_spot_lights_basic,texture_rgb,texture_luminance_alpha,transparent_overlap,depth_buffer_basic,alpha_test_basic,transparency_depth_basic,transparency_order_basic,specular_shininess_basic")
set(COIN_RASTER_VISUAL_SPECS
"raster_wide_line_basic,raster_line_pattern_basic,raster_points_basic,raster_wireframe_basic,image_basic")
set(COIN_TEXT_VISUAL_SPECS
"text2_layout_basic")
add_test(NAME visual_smoke COMMAND CoinVisualTests snapshot --help)
Expand Down Expand Up @@ -1022,6 +1024,46 @@ if(COIN_BUILD_VISUAL_TESTS)
)
set_tests_properties(visual_gl_drawlist_material_core
PROPERTIES LABELS "visual-material")
add_test(
NAME visual_gl_drawlist_text_compat
COMMAND CoinVisualTests run
--renderer drawlist
--gl-profile compat
--only ${COIN_TEXT_VISUAL_SPECS}
--artifacts-dir ${CMAKE_BINARY_DIR}/render_artifacts
)
set_tests_properties(visual_gl_drawlist_text_compat
PROPERTIES LABELS "visual-text")
add_test(
NAME visual_gl_drawlist_text_core
COMMAND CoinVisualTests run
--renderer drawlist
--gl-profile core
--only ${COIN_TEXT_VISUAL_SPECS}
--artifacts-dir ${CMAKE_BINARY_DIR}/render_artifacts
)
set_tests_properties(visual_gl_drawlist_text_core
PROPERTIES LABELS "visual-text")
add_test(
NAME visual_gl_drawlist_raster_compat
COMMAND CoinVisualTests run
--renderer drawlist
--gl-profile compat
--only ${COIN_RASTER_VISUAL_SPECS}
--artifacts-dir ${CMAKE_BINARY_DIR}/render_artifacts
)
set_tests_properties(visual_gl_drawlist_raster_compat
PROPERTIES LABELS "visual-raster")
add_test(
NAME visual_gl_drawlist_raster_core
COMMAND CoinVisualTests run
--renderer drawlist
--gl-profile core
--only ${COIN_RASTER_VISUAL_SPECS}
--artifacts-dir ${CMAKE_BINARY_DIR}/render_artifacts
)
set_tests_properties(visual_gl_drawlist_raster_core
PROPERTIES LABELS "visual-raster")
add_test(
NAME visual_gl_invalid_legacy_profile
COMMAND CoinVisualTests run
Expand Down
10 changes: 10 additions & 0 deletions data/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,16 @@ endmacro()
# embedded as independent C++ resources.
coin_embed_gl_shader(gl_visual_vertex data/shaders/gl/visual/Vertex.glsl)
coin_embed_gl_shader(gl_visual_fragment data/shaders/gl/visual/Fragment.glsl)
coin_embed_gl_shader(gl_wide_line_vertex data/shaders/gl/wide-line/Vertex.glsl)
coin_embed_gl_shader(gl_wide_line_geometry data/shaders/gl/wide-line/Geometry.glsl)
coin_embed_gl_shader(gl_wide_line_triangle_geometry data/shaders/gl/wide-line/TriangleGeometry.glsl)
coin_embed_gl_shader(gl_wide_line_fragment data/shaders/gl/wide-line/Fragment.glsl)
coin_embed_gl_shader(gl_point_vertex data/shaders/gl/point/Vertex.glsl)
coin_embed_gl_shader(gl_point_geometry data/shaders/gl/point/Geometry.glsl)
coin_embed_gl_shader(gl_point_triangle_geometry data/shaders/gl/point/TriangleGeometry.glsl)
coin_embed_gl_shader(gl_point_fragment data/shaders/gl/point/Fragment.glsl)
coin_embed_gl_shader(gl_pixel_vertex data/shaders/gl/pixel/Vertex.glsl)
coin_embed_gl_shader(gl_pixel_fragment data/shaders/gl/pixel/Fragment.glsl)

# These are legacy shader snippets exposed through Coin's built-in shader
# dictionary. They are ordinary embedded text, not core-profile root
Expand Down
36 changes: 36 additions & 0 deletions data/shaders/gl/pixel/Common.glsl
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
/*
* Pixel-raster coordinate and source-sampling helpers.
*
* Pixel producers provide final RGBA. The destination raster footprint and
* source texture size are independent, so scaled images map destination
* pixels back to source texels here. Inherited material and scene-texture
* state must not modulate the sampled pixel.
*/

vec2 coin_pixel_raster_coordinate(vec2 fragCoord,
vec2 viewportOrigin,
vec2 pixelOrigin)
{
return floor(fragCoord - viewportOrigin - pixelOrigin);
}

bool coin_pixel_in_raster(vec2 rasterPixel, vec2 rasterSize)
{
return rasterPixel.x >= 0.0 && rasterPixel.y >= 0.0 &&
rasterPixel.x < rasterSize.x && rasterPixel.y < rasterSize.y;
}

ivec2 coin_pixel_source_coordinate(vec2 rasterPixel,
vec2 sourceSize,
vec2 rasterSize,
ivec2 textureSizePixels)
{
ivec2 sourcePixel = ivec2(floor(rasterPixel * sourceSize /
max(rasterSize, vec2(1.0))));
return clamp(sourcePixel, ivec2(0), textureSizePixels - ivec2(1));
}

vec4 coin_pixel_fetch(sampler2D textureSampler, ivec2 pixel)
{
return texelFetch(textureSampler, pixel, 0);
}
33 changes: 33 additions & 0 deletions data/shaders/gl/pixel/Fragment.glsl
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
#version 330 core

/* Pixel fragment root. Pixel texels are final producer RGBA; only explicit
* pixel alpha-test state determines whether a covered fragment survives. */
uniform sampler2D u_texture;
uniform int u_alphaTestFunction;
uniform float u_alphaTestReference;
uniform vec2 u_sourceSize;
uniform vec2 u_rasterSize;
uniform vec2 u_pixelOrigin;
uniform vec2 u_viewportOrigin;

out vec4 fragColor;

#include "Common.glsl"
#include "../material/AlphaTest.glsl"

void main()
{
vec2 rasterPixel = coin_pixel_raster_coordinate(
gl_FragCoord.xy, u_viewportOrigin, u_pixelOrigin);
if (!coin_pixel_in_raster(rasterPixel, u_rasterSize)) {
discard;
}
ivec2 sourcePixel = coin_pixel_source_coordinate(
rasterPixel, u_sourceSize, u_rasterSize, textureSize(u_texture, 0));
vec4 texel = coin_pixel_fetch(u_texture, sourcePixel);
// Pixel producers retain final RGBA. Unlike ordinary surface commands,
// image/text pixels must not be modulated by inherited material state.
if (!coin_material_alpha_test_pass(texel.a, u_alphaTestFunction,
u_alphaTestReference)) discard;
fragColor = texel;
}
25 changes: 25 additions & 0 deletions data/shaders/gl/pixel/Vertex.glsl
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
#version 330 core

/* Pixel vertex root. It places a producer-supplied screen-space raster in
* the active viewport; source-texture lookup belongs to pixel/Common.glsl. */
layout(location = 0) in vec3 a_position;
layout(location = 3) in vec2 a_texcoord;

uniform mat4 u_proj;
uniform mat4 u_view;
uniform mat4 u_model;
uniform vec3 u_quadCenter;
uniform vec2 u_rasterSize;
uniform vec2 u_vpSize;
uniform vec2 u_pixelOrigin;

void main()
{
vec2 pixelPosition = u_pixelOrigin + a_texcoord * u_rasterSize;
// pixelOrigin is retained relative to the active viewport. Convert that
// local position directly to NDC; the viewport origin is supplied to the
// fragment shader only to translate gl_FragCoord back into the same space.
vec2 ndcPosition = 2.0 * pixelPosition / u_vpSize - 1.0;
vec4 centerClip = u_proj * u_view * u_model * vec4(u_quadCenter, 1.0);
gl_Position = vec4(ndcPosition * centerClip.w, centerClip.z, centerClip.w);
}
18 changes: 18 additions & 0 deletions data/shaders/gl/point/Fragment.glsl
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
#version 330 core

/* Point fragment root: generated point coverage shares surface evaluation
* with the ordinary visual pipeline and keeps alpha testing explicit. */
#include "../material/FragmentEvaluation.glsl"

in vec4 v_color;
in vec3 v_litColor;
in vec2 v_texcoord;
out vec4 fragColor;

void main()
{
vec4 color = coin_surface_fragment_color(v_color, v_litColor, v_texcoord);
if (!coin_material_alpha_test_pass(color.a, u_alphaTestFunction,
u_alphaTestReference)) discard;
fragColor = color;
}
38 changes: 38 additions & 0 deletions data/shaders/gl/point/Geometry.glsl
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
#version 330 core

/* Expands points into viewport-sized coverage quads when native point size
* is insufficient. The generated triangles are implementation detail; the
* input point remains the semantic primitive. */
layout(points) in;
layout(triangle_strip, max_vertices = 4) out;

uniform vec2 u_vpSize;
uniform float u_pointSize;

in vec4 vs_color[];
in vec3 vs_litColor[];
in vec2 vs_texcoord[];
out vec4 v_color;
out vec3 v_litColor;
out vec2 v_texcoord;

void coin_emit_point_corner(vec2 uv)
{
vec4 center = gl_in[0].gl_Position;
vec2 pixelOffset = (uv - vec2(0.5)) * u_pointSize;
vec2 ndcOffset = 2.0 * pixelOffset / u_vpSize;
gl_Position = center + vec4(ndcOffset * center.w, 0.0, 0.0);
v_color = vs_color[0];
v_litColor = vs_litColor[0];
v_texcoord = vs_texcoord[0];
EmitVertex();
}

void main()
{
coin_emit_point_corner(vec2(0.0, 1.0));
coin_emit_point_corner(vec2(0.0, 0.0));
coin_emit_point_corner(vec2(1.0, 1.0));
coin_emit_point_corner(vec2(1.0, 0.0));
EndPrimitive();
}
47 changes: 47 additions & 0 deletions data/shaders/gl/point/TriangleGeometry.glsl
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
#version 330 core

/* Expands triangle point coverage into one quad per source vertex after
* source-facing and strip-parity decisions. */
layout(triangles) in;
layout(triangle_strip, max_vertices = 12) out;

uniform vec2 u_vpSize;
uniform float u_pointSize;

#include "../visual/TriangleFallback.glsl"

in vec4 vs_color[];
in vec3 vs_litColor[];
in vec2 vs_texcoord[];
out vec4 v_color;
out vec3 v_litColor;
out vec2 v_texcoord;

void coin_emit_point_corner(int index, vec2 uv)
{
vec4 center = gl_in[index].gl_Position;
vec2 pixelOffset = (uv - vec2(0.5)) * u_pointSize;
vec2 ndcOffset = 2.0 * pixelOffset / u_vpSize;
gl_Position = center + vec4(ndcOffset * center.w, 0.0, 0.0);
v_color = vs_color[index];
v_litColor = vs_litColor[index];
v_texcoord = vs_texcoord[index];
EmitVertex();
}

void coin_emit_point(int index)
{
coin_emit_point_corner(index, vec2(0.0, 1.0));
coin_emit_point_corner(index, vec2(0.0, 0.0));
coin_emit_point_corner(index, vec2(1.0, 1.0));
coin_emit_point_corner(index, vec2(1.0, 0.0));
EndPrimitive();
}

void main()
{
if (coin_triangle_is_culled()) return;
coin_emit_point(0);
coin_emit_point(1);
coin_emit_point(2);
}
25 changes: 25 additions & 0 deletions data/shaders/gl/point/Vertex.glsl
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
#version 330 core

#include "../material/VertexEvaluation.glsl"

layout(location = 0) in vec3 a_position;
layout(location = 1) in vec3 a_normal;
layout(location = 2) in vec4 a_color;
layout(location = 3) in vec2 a_texcoord;


out vec4 vs_color;
out vec3 vs_litColor;
out vec2 vs_texcoord;

void main()
{
vs_color = coin_surface_vertex_color(a_color);
vs_texcoord = a_texcoord;
vec4 worldPos = u_model * vec4(a_position, 1.0);
vec4 eyePos = u_view * worldPos;
mat3 normalMatrix = transpose(inverse(mat3(u_view * u_model)));
vec3 eyeNormal = normalMatrix * a_normal;
vs_litColor = coin_surface_lit_color(vs_color, eyePos.xyz, eyeNormal);
gl_Position = u_proj * eyePos;
}
22 changes: 22 additions & 0 deletions data/shaders/gl/visual/TriangleFallback.glsl
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
// Shared state for triangle-to-line/point emulation. The geometry shader
// must apply culling to the source triangle before it emits coverage quads;
// culling those generated quads would not reproduce polygon culling.

uniform float u_cullBackFaces;
uniform float u_frontFaceCCW;

bool coin_triangle_front_facing()
{
vec2 p0 = gl_in[0].gl_Position.xy / gl_in[0].gl_Position.w;
vec2 p1 = gl_in[1].gl_Position.xy / gl_in[1].gl_Position.w;
vec2 p2 = gl_in[2].gl_Position.xy / gl_in[2].gl_Position.w;
vec2 d0 = p1 - p0;
vec2 d1 = p2 - p0;
bool ccw = d0.x * d1.y - d0.y * d1.x > 0.0;
return u_frontFaceCCW > 0.5 ? ccw : !ccw;
}

bool coin_triangle_is_culled()
{
return u_cullBackFaces > 0.5 && !coin_triangle_front_facing();
}
26 changes: 26 additions & 0 deletions data/shaders/gl/wide-line/Fragment.glsl
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
#version 330 core

/* Wide-line fragment root: stipple coverage first, shared surface
* evaluation second, explicit alpha testing last. */
#include "../material/FragmentEvaluation.glsl"
uniform int u_stipplePattern;
uniform float u_stippleScale;

in vec4 v_color;
in vec3 v_litColor;
in vec2 v_texcoord;
noperspective in float v_lineDistance;

out vec4 fragColor;

void main()
{
int bit = int(floor(max(v_lineDistance, 0.0) /
max(u_stippleScale, 1.0))) & 15;
if (((u_stipplePattern >> bit) & 1) == 0) discard;

vec4 color = coin_surface_fragment_color(v_color, v_litColor, v_texcoord);
if (!coin_material_alpha_test_pass(color.a, u_alphaTestFunction,
u_alphaTestReference)) discard;
fragColor = color;
}
Loading
Loading