Fills the flat cross-section where the clipping plane cuts a solid, so a
clipped closed solid reads as a slice instead of a hollow shell. For a
volumetric input (a Linear_cell_complex) each volume's cross-section is
filled in that volume's color.
The clipped solid is drawn into the stencil with an even-odd rule and a
quad on the plane is filled where the stencil is odd. Per-volume color
uses a dedicated cap buffer (POS_CAP_FACES) holding each volume's full
closed boundary (shared walls kept, unlike the de-duplicated display
buffer), so each volume is closed on its own; a surface mesh has no
groups and caps grey from the display buffer. The stencil buffer is
requested in init_ogl_context.
Draft: a K key toggles the cap, the cap buffer is built eagerly, and
only the two solid clip modes are capped.
## Description
### Summary of Changes
Improves the edge and vertex rendering of the Basic_viewer, following
the GSoC "Shaders for Basic Viewer" project idea. It rewrites the
wide-edge geometry shader to be more robust, draws the flat edges opaque
(anti-aliased by multisampling), fills the tube-edge joins with spheres
drawn from the edges, makes the on-screen sizing scale-independent,
correct on HiDPI displays, and consistent between the flat and cylinder
modes, fixes the Shift and minus size key, and removes a now-unused
uniform.
### What this changes
**Edge geometry shader**
- Builds the wide-edge quad in clip space instead of using a per-vertex
`inverse(u_Mvp)`. Since NDC = clip.xy / clip.w, a screen-space offset
becomes offset * w in clip space, so the quad vertices are emitted
directly with the correct depth and no matrix inverse. This is
numerically more stable and a little cheaper per edge.
- Removes the dangling `g_Color[]` input.
**Flat edges (opaque, anti-aliased by multisampling)**
- The flat edges are drawn opaque, and 4x framebuffer multisampling
smooths the silhouette, so they stay fully solid at any width and a thin
edge no longer fades toward the background. The earlier version blended
an analytical coverage alpha in the fragment shader, which left a faint
one-pixel border that read as slightly transparent; multisampling does
the anti-aliasing instead and keeps the edge solid.
- The geometry shader emits the exact square-capped edge rectangle, and
the minimum one-pixel half-width clamp keeps a sub-pixel edge solid.
Square caps are kept (see the note below).
**Tube edges (Ctrl+E)**
- The cylinder-edge mode fills the joints where the open tubes meet by
drawing a small sphere at each edge endpoint, in the cylinder color, the
analogue of ParaView's `RenderLinesAsTubes` plus
`RenderPointsAsSpheres`.
- The spheres are drawn from the edges, not from the scene's point set.
Drawing from the point set could place a sphere where no cylinder is: a
2D triangulation's point set includes its infinite vertex, and some
meshes include the endpoint of a zero-length degenerate edge whose
cylinder is invisible but whose sphere still shows, which appeared as a
stray floating mark near a junction. A geometry shader now takes each
edge, skips it when its two endpoints coincide, and emits a sphere at
each endpoint, so a sphere only ever lands where a real tube ends.
- Each endpoint sphere takes that endpoint's color, so the joints match
the cylinders even when the edges are colored individually.
- Known limitation: at very large edge widths the join sphere does not
completely fill the sharp corner where three thick tubes meet, so a thin
sliver of the face can show. At normal sizes it is clean. A better
large-width join is planned on a follow-up branch.
**Sizing**
- Edge width and vertex size are constant screen-pixel sizes,
independent of the scene scale and identical in 2D and 3D, so the
initial size is correct for a mesh at any scale and the +/- step is a
consistent pixel increment. Previously they were derived from the
bounding-box diagonal, which made flat edges sub-pixel on small meshes
and oversized on large ones.
- The cylinder (tube) radius and the sphere-vertex radius follow the
same screen-pixel size as the flat edges and points, using the camera
pixel-to-world ratio (`pixelGLRatio`), so a size-N edge is about N
pixels thick in both flat and tube mode, and a vertex matches between
the point and sphere modes. When zoomed in very close the tube looks
slightly thicker, since it is real 3D geometry while the flat edge is
screen space, but at normal framing they match.
**Size keys**
- Shift and the minus key now decreases the edge and vertex size. The
handlers matched `Qt::Key_Minus`, but on most keyboard layouts Shift and
minus reports `Qt::Key_Underscore`, so decreasing was silently ignored
while Shift and plus (which reports `Key_Plus`) worked. The minus
handlers now also accept `Key_Underscore`, for both the edge size and
the Ctrl vertex size. This was pre-existing in the size-key handling,
not introduced by the shader work.
**HiDPI / thin-edge fix**
- The edge and point sizes are scaled by the device pixel ratio to match
`u_Viewport`, so edges are not drawn too thin on HiDPI displays.
- The geometry shader clamps a minimum half-width, so a very thin edge
keeps a solid one-pixel core instead of fading into the background
color.
**Cleanup**
- Removes the now-unused `u_IsOrthographic` uniform and its setters (the
orthographic special-case was dropped when the sizes became constant
pixels).
### Testing
Tested on a hexahedron (3D), a 2D Delaunay triangulation, and a dense
surface mesh, at unit scale and at about 500-unit scale, with flat edges
and with tube edges (Ctrl+E), and at a simulated 2x HiDPI display. Edges
and vertices render with the correct, consistent size and color in all
cases, including after pressing +/- and Shift and minus to change the
size. The flat edges stay solid down to the smallest size, the flat and
tube thicknesses match at the same size, and the clipping-plane and
transparent rendering path still works. The tube joins are filled with
no stray sphere on the 2D triangulation (infinite vertex) or on a mesh
with a degenerate edge, and a clean cube fills correctly. Before/after
screenshots are on the CGAL wiki.
### Note on caps (square vs round)
Flat edges use square caps. Round caps fill the corners where two edges
meet but add a slight rounded bulge at free ends, and on a dense mesh at
large width they overshoot each vertex and overlap into a fish-scale
pattern. Square caps avoid that and only leave a small corner gap that
shows at large width. After comparing both on real renders and
discussing with the mentors, square caps are kept as the default, with
round documented as the alternative. The filled-join case is the tube
mode (cylinders plus per-endpoint spheres).
The flat edges used analytical anti-aliasing in the fragment shader, which left a one-pixel blended border that read as slightly transparent, and a very thin edge could fade toward the background. Draw the edges opaque instead: the geometry shader emits the exact square-capped edge rectangle, the fragment shader outputs the solid edge colour (keeping the clipping-plane discard), and 4x multisampling is enabled on the context to smooth the silhouette. A thin edge now stays fully solid at any width. The minimum one-pixel half-width clamp is kept so a sub-pixel edge keeps a solid core.
The modern Basic_viewer shaders are all #version 150 (OpenGL 3.2), but
shader selection was gated on isOpenGL_4_3(). On core-profile contexts
below 4.3 (e.g. macOS 4.1 core) this routed to the compatibility shaders,
which use legacy GLSL and do not compile on a core profile.
Add a separate is_ogl_3_2 / isOpenGL_3_2() capability flag and use it for
Basic_viewer's modern-vs-compatibility shader selection. isOpenGL_4_3() is
left unchanged because outside Basic_viewer it still gates the OpenGL 4.3
C++ API (QOpenGLFunctions_4_3_Core) used by the CGAL Lab demo and Three.
## Summary of Changes
Previously, left-clicking to orbit the camera while a path was playing
would directly modify the camera transform, corrupting the ongoing
interpolation. Stopping the path playback on a mouse press assumes the
user intentionally wants to interrupt it.
## Release Management
* Affected package(s): Basic_Viewer, GraphicsView
## Summary of Changes
Suppress
[warning](https://cgal.geometryfactory.com/CGAL/testsuite/CGAL-6.2-Ic-134/Lab_Demo/TestReport_lrineau_Ubuntu-latest-GCC6-CXX1z.gz)
issued by gcc.
```
include/CGAL/Three/Viewer_interface.h:42:21: warning: defining ‘CGAL::Three::Viewer_interface’, which previously failed to be complete in a SFINAE context [-Wsfinae-incomplete=]
42 | class VIEWER_EXPORT Viewer_interface : public CGAL::QGLViewer{
| ^~~~~~~~~~~~~~~~
```
## Release Management
* Affected package(s): Lab
* License and copyright ownership: unchanged
- Add bindAttributeLocation(a_Pos, 0) and bindAttributeLocation(a_Color, 1)
before link() for rendering_program_p_l, rendering_program_line, and
rendering_program_cylinder to guarantee consistent attribute locations
across all OpenGL drivers.
- Remove dead 'in mediump vec4 g_Color[]' from GEOMETRY_SOURCE_LINE_WIDTH
geometry shader (no matching vertex shader output).
- Add proper edge rendering fallback via rendering_program_p_l for
OpenGL < 4.3 where the geometry shader is unavailable.
- Re-add minor version check for OpenGL 4.0-4.2 in qglviewer_impl.h.
- Version check: revert to majorVersion() < 4 instead of checking for
specifically 4.3. On macOS, init_ogl_context() caps to 4.1 core
profile; compat shaders (attribute/varying) would fail in core
contexts. The #version 150 modern shaders work fine on any 4.x.
This also correctly handles future OpenGL 5+.
- Warning: use static guard so the message emits only once, even if
compile_shaders() is called multiple times.
Fix compatibility shaders and OpenGL version detection that caused
CGAL::draw() to render solid black geometry on systems with OpenGL < 4.3.
Basic_shaders.h:
- VERTEX_SOURCE_COLOR_COMP: change 'varying' to 'attribute' for vertex
inputs (a_Pos, a_Normal, a_Color) as required by GLSL 1.10/1.20
- VERTEX_SOURCE_COLOR_COMP: replace undefined 'mv_matrix' reference with
'mat3(u_Mv) * a_Normal' matching the declared uniform
- VERTEX_SOURCE_P_L_COMP: change 'varying' to 'attribute' for vertex
inputs (a_Pos, a_Color)
qglviewer_impl.h:
- Initialize is_ogl_4_3 to false in defaultConstructor() to avoid UB
- Fix version check: use major < 4 || (major == 4 && minor < 3) instead
of major != 4, so OpenGL 4.0-4.2 correctly falls back and 5+ works
Basic_viewer.h:
- Add std::cerr warning when compatibility shaders are selected