mirror of https://github.com/mosra/magnum.git
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1178 lines
50 KiB
1178 lines
50 KiB
#ifndef Magnum_Shaders_LineGL_h |
|
#define Magnum_Shaders_LineGL_h |
|
/* |
|
This file is part of Magnum. |
|
|
|
Copyright © 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019, |
|
2020, 2021, 2022, 2023 Vladimír Vondruš <mosra@centrum.cz> |
|
|
|
Permission is hereby granted, free of charge, to any person obtaining a |
|
copy of this software and associated documentation files (the "Software"), |
|
to deal in the Software without restriction, including without limitation |
|
the rights to use, copy, modify, merge, publish, distribute, sublicense, |
|
and/or sell copies of the Software, and to permit persons to whom the |
|
Software is furnished to do so, subject to the following conditions: |
|
|
|
The above copyright notice and this permission notice shall be included |
|
in all copies or substantial portions of the Software. |
|
|
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
|
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING |
|
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER |
|
DEALINGS IN THE SOFTWARE. |
|
*/ |
|
|
|
#ifndef MAGNUM_TARGET_GLES2 |
|
/** @file |
|
* @brief Class @ref Magnum::Shaders::LineGL, typedef @ref Magnum::Shaders::LineGL2D, @ref Magnum::Shaders::LineGL3D |
|
* @m_since_latest |
|
*/ |
|
#endif |
|
|
|
#include <Corrade/Utility/Move.h> |
|
|
|
#include "Magnum/DimensionTraits.h" |
|
#include "Magnum/GL/AbstractShaderProgram.h" |
|
#include "Magnum/Shaders/GenericGL.h" |
|
#include "Magnum/Shaders/glShaderWrapper.h" |
|
#include "Magnum/Shaders/visibility.h" |
|
|
|
#ifndef MAGNUM_TARGET_GLES2 |
|
namespace Magnum { namespace Shaders { |
|
|
|
namespace Implementation { |
|
enum class LineGLFlag: UnsignedShort { |
|
VertexColor = 1 << 0, |
|
ObjectId = 1 << 1, |
|
InstancedObjectId = (1 << 2)|ObjectId, |
|
InstancedTransformation = 1 << 3, |
|
UniformBuffers = 1 << 4, |
|
#ifndef MAGNUM_TARGET_WEBGL |
|
ShaderStorageBuffers = UniformBuffers|(1 << 6), |
|
#endif |
|
MultiDraw = UniformBuffers|(1 << 5) |
|
}; |
|
typedef Containers::EnumSet<LineGLFlag> LineGLFlags; |
|
CORRADE_ENUMSET_OPERATORS(LineGLFlags) |
|
} |
|
|
|
/** |
|
@brief Line GL shader |
|
@m_since_latest |
|
|
|
Renders lines expanded to quads in screen space. Compared to builtin GPU line |
|
rendering, the lines can be of arbitrary width, with configurable join and cap |
|
styles, and antialiased independently of MSAA being used or not. |
|
|
|
@image html shaders-line.png width=256px |
|
|
|
@experimental |
|
|
|
@requires_gl30 Extension @gl_extension{EXT,gpu_shader4} |
|
@requires_gles30 Requires integer support in shaders which is not available in |
|
OpenGL ES 2.0. |
|
@requires_webgl20 Requires integer support in shaders which is not available in |
|
WebGL 1.0. |
|
|
|
@section Shaders-LineGL-usage Usage |
|
|
|
The shader doesn't work with @ref MeshPrimitive::Lines, |
|
@ref MeshPrimitive::LineStrip or @ref MeshPrimitive::LineLoop directly, as that |
|
would only be implementable with a relatively expensive geometry shader. |
|
Instead, it requires the input data to be organized in quads, with |
|
@ref Position, @ref PreviousPosition and @ref NextPosition attributes |
|
describing point wíth their surroundings, and @ref Annotation with |
|
point-specific annotation such as whether given point is a line cap or a join |
|
with neighboring segment. The data layout is described in detail in |
|
@ref Shaders-LineGL-mesh-representation below, however in practice it's easiest |
|
to convert an existing line @ref Trade::MeshData to a form accepted by this |
|
shader with @ref MeshTools::generateLines() and then compile it to a |
|
@ref GL::Mesh with @ref MeshTools::compileLines(): |
|
|
|
@snippet Shaders-gl.cpp LineGL-usage |
|
|
|
For rendering use @ref setTransformationProjectionMatrix(), |
|
@ref setColor(), @ref setWidth() and others. It's important to pass viewport |
|
size in @ref setViewportSize() as the line width is interpreted relative to it. |
|
|
|
@snippet Shaders-gl.cpp LineGL-usage2 |
|
|
|
@subsection Shaders-LineGL-usage-triangulation Line triangulation |
|
|
|
Each line segment is rendered as a quad consisting of two triangles. Standalone |
|
segments have cap style configurable via @ref Configuration::setCapStyle() with |
|
the following styles, segments of zero length can be also used to render |
|
points. The @m_span{m-label m-default} white @m_endspan lines show generated |
|
triangles, the @m_span{m-label m-info} blue @m_endspan line is the actually |
|
visible edge between foreground and background: |
|
|
|
@m_class{m-row} |
|
|
|
@parblock |
|
|
|
@m_div{m-col-l-6 m-text-center} |
|
@htmlinclude line-cap-butt.svg |
|
@ref LineCapStyle::Butt |
|
@m_enddiv |
|
|
|
@m_div{m-col-l-6 m-text-center} |
|
@htmlinclude line-cap-square.svg |
|
@ref LineCapStyle::Square |
|
@m_enddiv |
|
|
|
@m_div{m-col-l-6 m-text-center} |
|
@htmlinclude line-cap-round.svg |
|
@ref LineCapStyle::Round |
|
@m_enddiv |
|
|
|
@m_div{m-col-l-6 m-text-center} |
|
@htmlinclude line-cap-triangle.svg |
|
@ref LineCapStyle::Triangle |
|
@m_enddiv |
|
|
|
@endparblock |
|
|
|
Joins between consecutive segments in contiguous line strips are expanded to |
|
form a gap-less mesh without overlaps. Depending on join style picked in |
|
@ref Configuration::setJoinStyle() and angle between the segments the area |
|
between points `A`, `B` and `C` may be filled with another triangle: |
|
|
|
@m_class{m-row} |
|
|
|
@parblock |
|
|
|
@m_div{m-col-l-6 m-text-center} |
|
@htmlinclude line-join-miter.svg |
|
@ref LineJoinStyle::Miter |
|
@m_enddiv |
|
|
|
@m_div{m-col-l-6 m-text-center} |
|
@htmlinclude line-join-bevel.svg |
|
@ref LineJoinStyle::Bevel |
|
@m_enddiv |
|
|
|
@endparblock |
|
|
|
@subsection Shaders-LineGL-usage-antialiasing Antialiasing |
|
|
|
The lines aren't smoothed out by default, use @ref setSmoothness() to pick a |
|
tradeoff between the line being aliased and blurry. This is implemented by |
|
interpolating between the foreground color and the background, which assumes |
|
blending is set up for pre-multiplied alpha. If you're drawing lines on a |
|
single-color background, you can @ref setBackgroundColor() to a color matching |
|
the background and keep blending disabled, but note that you may get artifacts |
|
if the lines are self-overlapping. |
|
|
|
@snippet Shaders-gl.cpp LineGL-usage-antialiasing |
|
|
|
@subsection Shaders-LineGL-usage-3d Lines in 3D |
|
|
|
The 3D variant of this shader renders the geometry with depth values derived |
|
from the original line endpoints, however without any perspective shortening |
|
applied --- the line width is the same viewport-relative value independently of |
|
the depth the point is at. |
|
|
|
@section Shaders-LineGL-object-id Object ID output |
|
|
|
The shader supports writing object ID to the framebuffer for object picking or |
|
other annotation purposes. Enable it using @ref Flag::ObjectId and set up an |
|
integer buffer attached to the @ref ObjectIdOutput attachment. If you have a |
|
batch of meshes with different object IDs, enable @ref Flag::InstancedObjectId |
|
and supply per-vertex IDs to the @ref ObjectId attribute. The output will |
|
contain a sum of the per-vertex ID and ID coming from @ref setObjectId(). |
|
|
|
The functionality is practically the same as in the @ref FlatGL shader, see |
|
@ref Shaders-FlatGL-object-id "its documentation" for more information and usage |
|
example. |
|
|
|
Note that the object ID is emitted for the whole triangle area, including |
|
transparent areas of caps when using @ref LineCapStyle::Round or |
|
@ref LineCapStyle::Triangle as well as semi-transparent edges with smoothness |
|
values larger than zero. In particular, the object ID output will be aliased |
|
even if the color output isn't. |
|
|
|
@section Shaders-LineGL-instancing Instanced rendering |
|
|
|
Enabling @ref Flag::InstancedTransformation will turn the shader into an |
|
instanced one. It'll take per-instance transformation from the |
|
@ref TransformationMatrix attribute, applying it before the matrix set by |
|
@ref setTransformationProjectionMatrix(). Besides that, @ref Flag::VertexColor |
|
(and the @ref Color3 / @ref Color4) attributes can work as both per-vertex and |
|
per-instance. The functionality is practically the same as in the @ref FlatGL |
|
shader, see @ref Shaders-FlatGL-instancing "its documentation" for more |
|
information and usage example. |
|
|
|
@requires_gl33 Extension @gl_extension{ARB,instanced_arrays} |
|
|
|
@section Shaders-LineGL-ubo Uniform buffers |
|
|
|
See @ref shaders-usage-ubo for a high-level overview that applies to all |
|
shaders. In this particular case, because the shader doesn't need a separate |
|
projection and transformation matrix, a combined one is supplied via a |
|
@ref TransformationProjectionUniform2D / @ref TransformationProjectionUniform3D |
|
buffer bound with @ref bindTransformationProjectionBuffer(). To maximize use of the limited uniform buffer memory, materials are supplied separately in a |
|
@ref LineMaterialUniform buffer bound with @ref bindMaterialBuffer() and then |
|
referenced via @relativeref{LineDrawUniform,materialId} from a |
|
@ref LineDrawUniform bound with @ref bindDrawBuffer(). A uniform buffer setup |
|
equivalent to the @ref Shaders-LineGL-usage "snippet at the top" would look |
|
like this --- note that @ref setViewportSize() is an immediate uniform |
|
here as well, as it's assumed to be set globally and rarely changed: |
|
|
|
@snippet Shaders-gl.cpp LineGL-ubo |
|
|
|
For a multidraw workflow enable @ref Flag::MultiDraw and supply desired |
|
material and draw count via @ref Configuration::setMaterialCount() and |
|
@relativeref{Configuration,setDrawCount()}. For every draw then specify |
|
material references. Besides that, the usage is similar for all shaders, see |
|
@ref shaders-usage-multidraw for an example. |
|
|
|
@requires_gl31 Extension @gl_extension{ARB,uniform_buffer_object} for uniform |
|
buffers. |
|
@requires_gl46 Extension @gl_extension{ARB,shader_draw_parameters} for |
|
multidraw. |
|
@requires_es_extension Extension @m_class{m-doc-external} [ANGLE_multi_draw](https://chromium.googlesource.com/angle/angle/+/master/extensions/ANGLE_multi_draw.txt) |
|
(unlisted) for multidraw. |
|
@requires_webgl_extension Extension @webgl_extension{ANGLE,multi_draw} for |
|
multidraw. |
|
|
|
@section Shaders-LineGL-mesh-representation Line mesh representation |
|
|
|
In order to avoid performing expensive CPU-side expansion of the quads every |
|
time the transformation, line width and other parameters change, the shader |
|
gets just the original line segment endpoints as an input, transforms them in |
|
2D or 3D as usual, and then expands them in screen space for a desired line |
|
width. |
|
|
|
@htmlinclude line-quad-expansion.svg |
|
|
|
Ignoring all complexity related to line caps and joins for now, an example |
|
expansion of three line segments into quads is shown above --- the first two |
|
segments form a join at the @m_span{m-label m-info} blue @m_endspan point, the |
|
third segment is standalone. In order to form a quad, each of the points has |
|
to be present twice in the vertex stream, with first copy expanding up and |
|
second copy expanding down. The @ref Position data needed to render quads would |
|
then look like below, color-coded to match the above, and in order following |
|
the segment direction. An index buffer would then form two triangles out of |
|
every four points --- @cpp {0, 1, 2, 2, 1, 3, …} @ce. |
|
|
|
@htmlinclude line-quad-data.svg |
|
|
|
To figure out the direction in which to expand, for given endpoint position the |
|
shader needs also *screen-space direction* to the other endpoint. But since a |
|
2D / 3D transformation has to be applied for both endpoints before calculating |
|
their screen-space position, it makes more sense to supply directly its |
|
position instead, and calculate the direction only after transforming both |
|
points. The input data would then look like this, with "previous" positions |
|
shown above and "next" positions shown below: |
|
|
|
@htmlinclude line-quad-data-other.svg |
|
|
|
With line joins and caps present, the quad expansion changes in the following |
|
way. In the general case, to avoid overlapping geometry and gaps, points `B` |
|
and `D` collapse to a single position and the area in between is filled with an |
|
extra triangle. Depending on the transformation, it can however also happen |
|
that `A` and `C` collapse into a single point instead, for example if the |
|
@m_span{m-label m-primary} azure @m_endspan point would appear above the |
|
@m_span{m-label m-success} green @m_endspan one instead of below. Thus the |
|
index buffer needs to handle both cases --- @cpp {…, 2, 3, 4, 4, 3, 5, …} @ce |
|
--- and one of them always denegerates to a zero-area triangle. |
|
|
|
@htmlinclude line-quad-expansion-joins-caps.svg |
|
|
|
To handle the join, the shader needs to know whether there's a neighboring line |
|
segment to join with, and what is the position of its other endpoint. Thus, |
|
every vertex gets *two* neighboring positions, a @ref PreviousPosition and a |
|
@ref NextPosition. Both of them are filled only in case the point forms a line |
|
join; if the point is a line cap, one of them is left unspecified. |
|
|
|
@htmlinclude line-quad-data-neighbor.svg |
|
|
|
What's left is giving the shader an ability to distinguish the direction in |
|
which to expand the point (@ref LineVertexAnnotation::Up or downwards), whether |
|
it's a @relativeref{LineVertexAnnotation,Join} or a cap and whether the point |
|
is a @relativeref{LineVertexAnnotation,Begin} or an end of the segment in order |
|
to know what the neigboring positions represent. This info is stored in the |
|
@ref Annotation attribute and shown with `U`, `J` and `B` letters above. In |
|
this particular case the info could also be inferred from the vertex index and |
|
for example NaNs in the neigbor positions, but a dedicated attribute makes it |
|
more flexible for optimized data layouts explained below. |
|
|
|
@subsection Shaders-LineGL-data-representation-overlap Overlapping layouts with less data redundancy |
|
|
|
Assuming a 3D line mesh with floating-point position attributes, the |
|
@ref Annotation attribute packed into a single byte and |
|
@ref MeshIndexType::UnsignedShort indices, a a single contiguous line strip |
|
consisting of @f$ n @f$ line segments would need |
|
@f$ (4(36 + 1) + 24)n = 172n @f$ bytes of data. In comparison, |
|
CPU-side-generated indexed quads would need just |
|
@f$ (24 + 18)n + 24 = 42n + 24 @f$ bytes, and a (non-indexed) |
|
@ref MeshPrimitive::LineStrip only @f$ 12n + 12 @f$ bytes, which is ~14x less. |
|
Fortunately, the position data can be organized in a way that makes it possible |
|
to reuse them for previous and next positions as well, by binding the same data |
|
again under an offset. |
|
|
|
There's the following possibilites, each with different tradeoffs depending on |
|
the use case. Such data layout variants require no special-casing in the |
|
shader, only a different mesh setup, making it possible to pick the best option |
|
for each line mesh without having to pay for expensive shader switching. |
|
|
|
@subsubsection Shaders-LineGL-data-representation-overlap-nojoin Standalone line segments without joins |
|
|
|
If the mesh consists just of loose line segments and no joints need to be |
|
drawn, the @ref Position attribute can be bound with an offset of @cpp -2 @ce |
|
elements to the @ref PreviousPosition and @cpp +2 @ce elements to the |
|
@ref NextPosition. To avoid out-of-bound reads, the position buffer needs to be |
|
padded with two elements at the front and at the end. Together with no indices |
|
needed for joint triangles the memory requirement would be reduced to |
|
@f$ (4(12 + 1) + 12)n + 12 = 64 n + 12 @f$ bytes, which is roughly the same |
|
amount of data as for loose CPU-side-generated indexed quads, and ~2.7x as much |
|
as @f$ 24n @f$ bytes a sufficiently large (non-indexed) |
|
@ref MeshPrimitive::Lines would need. |
|
|
|
@m_div{m-row m-container-inflate} |
|
@m_div{m-col-l-12 m-nopady m-nopadx} |
|
@htmlinclude line-quad-data-overlap-nojoin.svg |
|
@m_enddiv |
|
@m_enddiv |
|
|
|
@subsubsection Shaders-LineGL-data-representation-overlap-generic Generic lines |
|
|
|
For arbitrary lines that consist of both joined strips and standalone segments |
|
and the joins can be of any style in any direction, the @ref Position attribute |
|
has to be additionally padded with two elements at begin and end of every |
|
contiguous line strip together with skipping the elements in the index buffer |
|
appropriately, and then bound with an offset of @cpp -4 @ce elements to the |
|
@ref PreviousPosition and @cpp +4 @ce elements to the @ref NextPosition. |
|
|
|
This needs only one triangle in the index buffer for each join instead of two |
|
and has a memory requirement of |
|
@f$ (4(12 + 1) + 24)n + (4(12 + 1) - 12)l + 12 @f$ bytes, with @f$ l @f$ |
|
being the line strip count. With a mesh consisting of just a single strip this |
|
is @f$ 76n + 52 @f$ bytes, which is ~1.8x as much as CPU-side-generated indexed |
|
quads and ~6.3x as much as a @ref MeshPrimitive::LineStrip would need. |
|
|
|
@m_div{m-row m-container-inflate} |
|
@m_div{m-col-l-12 m-nopady m-nopadx} |
|
@htmlinclude line-quad-data-overlap-generic.svg |
|
@m_enddiv |
|
@m_enddiv |
|
|
|
@subsubsection Shaders-LineGL-data-representation-overlap-fixedjoin Lines with fixed join directions |
|
|
|
If the joint direction is known to be fixed, i.e. the B and D points always |
|
collapse to the same position independently of the transform used, the two |
|
points can be replaced with just one. This is commonly the case in 2D if |
|
negative transformation scaling isn't involved and with planar line art in 3D |
|
if it additionally also isn't viewed from the back side. This allows padding |
|
of the @ref Position attribute at the begin and end of every contiguous line |
|
strip to be reduced to just one element, binding it with an offset of |
|
@cpp -3 @ce elements to the @ref PreviousPosition and @cpp +3 @ce elements to |
|
the @ref NextPosition. |
|
|
|
This has a memory requirement of |
|
@f$ (3(12 + 1) + 18)n + (3(12 + 1) - 6)l + 12 @f$ bytes. With a mesh consisting |
|
of just a single strip this is @f$ 57n + 45 @f$ bytes, which is ~1.4x as much |
|
as CPU-side-generated indexed quads and ~4.75x as much as a |
|
@ref MeshPrimitive::LineStrip would need. |
|
|
|
@m_div{m-row m-container-inflate} |
|
@m_div{m-col-l-12 m-nopady m-nopadx} |
|
@htmlinclude line-quad-data-overlap-fixedjoin.svg |
|
@m_enddiv |
|
@m_enddiv |
|
|
|
@subsubsection Shaders-LineGL-data-representation-overlap-miterjoin Lines with miter joins only |
|
|
|
The final and most data-efficient case is for line meshes where the contiguous |
|
segments consist of miter joints only (i.e., with the assumption that the angle |
|
between two segments is never too sharp to fall back to |
|
@ref LineJoinStyle::Bevel), resulting in the join collapsing to just two |
|
vertices, with no triangle in between: |
|
|
|
@htmlinclude line-quad-expansion-joins-miter-caps.svg |
|
|
|
This is the usual case for finely subdivided curves. Generic line art can be |
|
patched in a preprocessing step, subdividing sharp corners to a sequence of |
|
joins with larger angles. This layout doesn't require any padding of the |
|
@ref Position attribute between contiguous line strips, and it's bound with an |
|
offset of @cpp -2 @ce elements to the @ref PreviousPosition and @cpp +2 @ce |
|
elements to the @ref NextPosition. |
|
|
|
The memory requirement is @f$ (2(12 + 1) + 12)n + 2(12 + 1)l + 12 @f$ bytes. |
|
With a mesh consisting of a single strip it's @f$ 38n + 38 @f$ bytes. This is |
|
roughly the same memory use as @f$ 36n + 24 @f$ bytes for CPU-side-generated |
|
quads with miter joins only, and ~3.2x as much as a |
|
@ref MeshPrimitive::LineStrip would need. |
|
|
|
@m_div{m-row m-container-inflate} |
|
@m_div{m-col-l-12 m-nopady m-nopadx} |
|
@htmlinclude line-quad-data-overlap-miterjoin.svg |
|
@m_enddiv |
|
@m_enddiv |
|
*/ |
|
template<UnsignedInt dimensions> class MAGNUM_SHADERS_EXPORT LineGL: public GL::AbstractShaderProgram { |
|
public: |
|
/* MSVC needs dllexport here as well */ |
|
class MAGNUM_SHADERS_EXPORT Configuration; |
|
class CompileState; |
|
|
|
/** |
|
* @brief Vertex position |
|
* |
|
* @ref shaders-generic "Generic attribute", |
|
* @relativeref{Magnum,Vector2} in 2D, @relativeref{Magnum,Vector3} in |
|
* 3D. |
|
*/ |
|
typedef typename GenericGL<dimensions>::Position Position; |
|
|
|
/** |
|
* @brief Previous position |
|
* |
|
* @relativeref{Magnum,Vector2} in 2D, @relativeref{Magnum,Vector3} in |
|
* 3D. Uses the same location as @ref GenericGL::Tangent with the |
|
* assumption that lines don't need tangent space information. |
|
* |
|
* If @ref LineVertexAnnotation::Begin is set in @ref Annotation, |
|
* contains the other point of the neighboring line segment if |
|
* @ref LineVertexAnnotation::Join is also set, and is ignored |
|
* otherwise. If @ref LineVertexAnnotation::Begin is not set in |
|
* @ref Annotation, contains the other point of the line segment. |
|
*/ |
|
typedef GL::Attribute<3, VectorTypeFor<dimensions, Float>> PreviousPosition; |
|
|
|
/** |
|
* @brief Next position |
|
* |
|
* @relativeref{Magnum,Vector2} in 2D, @relativeref{Magnum,Vector3} in |
|
* 3D. Uses the same location as @ref GenericGL::Normal with the |
|
* assumption that lines don't need tangent space information. |
|
* |
|
* If @ref LineVertexAnnotation::Begin is set in @ref Annotation, |
|
* contains the other point of the line segment. If |
|
* @ref LineVertexAnnotation::Begin is not set in @ref Annotation, |
|
* contains the other point of the neighboring line segment if |
|
* @ref LineVertexAnnotation::Join is set, and is ignored otherwise. |
|
*/ |
|
typedef GL::Attribute<5, VectorTypeFor<dimensions, Float>> NextPosition; |
|
|
|
/** |
|
* @brief Vertex annotation |
|
* |
|
* Uses the same location as @ref GenericGL::TextureCoordinates with |
|
* the assumption that lines don't need a two-dimensional texture |
|
* space information. |
|
* |
|
* Contains a set of @ref LineVertexAnnotation bits, see their |
|
* documentation for more information. The values are guaranteed to fit |
|
* into 8 bits. |
|
*/ |
|
typedef GL::Attribute<1, UnsignedInt> Annotation; |
|
|
|
/** |
|
* @brief Three-component vertex color |
|
* |
|
* @ref shaders-generic "Generic attribute", @ref Magnum::Color3. Use |
|
* either this or the @ref Color4 attribute. |
|
*/ |
|
typedef typename GenericGL<dimensions>::Color3 Color3; |
|
|
|
/** |
|
* @brief Four-component vertex color |
|
* |
|
* @ref shaders-generic "Generic attribute", @ref Magnum::Color4. Use |
|
* either this or the @ref Color3 attribute. |
|
*/ |
|
typedef typename GenericGL<dimensions>::Color4 Color4; |
|
|
|
/** |
|
* @brief (Instanced) object ID |
|
* |
|
* @ref shaders-generic "Generic attribute", |
|
* @relativeref{Magnum,UnsignedInt}. Used only if |
|
* @ref Flag::InstancedObjectId is set. |
|
*/ |
|
typedef typename GenericGL<dimensions>::ObjectId ObjectId; |
|
|
|
/** |
|
* @brief (Instanced) transformation matrix |
|
* |
|
* @ref shaders-generic "Generic attribute", |
|
* @relativeref{Magnum,Matrix3} in 2D, @relativeref{Magnum,Matrix4} in |
|
* 3D. Used only if @ref Flag::InstancedTransformation is set. |
|
* @requires_gl33 Extension @gl_extension{ARB,instanced_arrays} |
|
*/ |
|
typedef typename GenericGL<dimensions>::TransformationMatrix TransformationMatrix; |
|
|
|
enum: UnsignedInt { |
|
/** |
|
* Color shader output. Present always, expects three- or |
|
* four-component floating-point or normalized buffer attachment. |
|
*/ |
|
ColorOutput = GenericGL<dimensions>::ColorOutput, |
|
|
|
/** |
|
* Object ID shader output. @ref shaders-generic "Generic output", |
|
* present only if @ref Flag::ObjectId is set. Expects a |
|
* single-component unsigned integral attachment. Writes the value |
|
* set in @ref setObjectId() and possibly also a per-vertex ID and |
|
* an ID fetched from a texture, see @ref Shaders-LineGL-object-id |
|
* for more information. |
|
* @requires_gl30 Extension @gl_extension{EXT,texture_integer} |
|
*/ |
|
ObjectIdOutput = GenericGL<dimensions>::ObjectIdOutput |
|
}; |
|
|
|
#ifdef DOXYGEN_GENERATING_OUTPUT |
|
/** |
|
* @brief Flag |
|
* |
|
* @see @ref Flags, @ref flags(), @ref Configuration::setFlags() |
|
*/ |
|
enum class Flag: UnsignedShort { |
|
/** |
|
* Multiply the color with a vertex color. Requires either the |
|
* @ref Color3 or @ref Color4 attribute to be present. |
|
*/ |
|
VertexColor = 1 << 0, |
|
|
|
/** |
|
* Enable object ID output. See @ref Shaders-LineGL-object-id for |
|
* more information. |
|
*/ |
|
ObjectId = 1 << 1, |
|
|
|
/** |
|
* Instanced object ID. Retrieves a per-instance / per-vertex |
|
* object ID from the @ref ObjectId attribute, outputting a sum of |
|
* the per-vertex ID and ID coming from @ref setObjectId() or |
|
* @ref LineDrawUniform::objectId. Implicitly enables |
|
* @ref Flag::ObjectId. See @ref Shaders-LineGL-object-id for more |
|
* information. |
|
*/ |
|
InstancedObjectId = (1 << 2)|ObjectId, |
|
|
|
/** |
|
* Instanced transformation. Retrieves a per-instance |
|
* transformation matrix from the @ref TransformationMatrix |
|
* attribute and uses it together with the matrix coming from |
|
* @ref setTransformationProjectionMatrix() or |
|
* @ref TransformationProjectionUniform2D::transformationProjectionMatrix |
|
* / @ref TransformationProjectionUniform3D::transformationProjectionMatrix |
|
* (first the per-instance, then the uniform matrix). See |
|
* @ref Shaders-LineGL-instancing for more information. |
|
* @requires_gl33 Extension @gl_extension{ARB,instanced_arrays} |
|
*/ |
|
InstancedTransformation = 1 << 3, |
|
|
|
/** |
|
* Use uniform buffers. Expects that uniform data are supplied via |
|
* @ref bindTransformationProjectionBuffer(), |
|
* @ref bindDrawBuffer() and @ref bindMaterialBuffer() instead of |
|
* direct uniform setters. |
|
* @see @ref Flag::ShaderStorageBuffers |
|
* @requires_gl31 Extension @gl_extension{ARB,uniform_buffer_object} |
|
*/ |
|
UniformBuffers = 1 << 4, |
|
|
|
#ifndef MAGNUM_TARGET_WEBGL |
|
/** |
|
* Use shader storage buffers. Superset of functionality provided |
|
* by @ref Flag::UniformBuffers, compared to it doesn't have any |
|
* size limits on @ref Configuration::setMaterialCount() and |
|
* @relativeref{Configuration,setDrawCount()} in exchange for |
|
* potentially more costly access and narrower platform support. |
|
* @requires_gl43 Extension @gl_extension{ARB,shader_storage_buffer_object} |
|
* @requires_gles31 Shader storage buffers are not available in |
|
* OpenGL ES 3.0 and older. |
|
* @requires_gles Shader storage buffers are not available in |
|
* WebGL. |
|
* @m_since_latest |
|
*/ |
|
ShaderStorageBuffers = UniformBuffers|(1 << 6), |
|
#endif |
|
|
|
/** |
|
* Enable multidraw functionality. Implies @ref Flag::UniformBuffers |
|
* and adds the value from @ref setDrawOffset() with the |
|
* @glsl gl_DrawID @ce builtin, which makes draws submitted via |
|
* @ref GL::AbstractShaderProgram::draw(const Containers::Iterable<MeshView>&) |
|
* and related APIs pick up per-draw parameters directly, without |
|
* having to rebind the uniform buffers or specify |
|
* @ref setDrawOffset() before each draw. In a non-multidraw |
|
* scenario, @glsl gl_DrawID @ce is @cpp 0 @ce, which means a |
|
* shader with this flag enabled can be used for regular draws as |
|
* well. |
|
* @requires_gl46 Extension @gl_extension{ARB,uniform_buffer_object} |
|
* and @gl_extension{ARB,shader_draw_parameters} |
|
* @requires_es_extension OpenGL ES 3.0 and extension |
|
* @m_class{m-doc-external} [ANGLE_multi_draw](https://chromium.googlesource.com/angle/angle/+/master/extensions/ANGLE_multi_draw.txt) |
|
* (unlisted). While the extension alone needs only OpenGL ES |
|
* 2.0, the shader implementation relies on uniform buffers, |
|
* which require OpenGL ES 3.0. |
|
* @requires_webgl_extension WebGL 2.0 and extension |
|
* @webgl_extension{ANGLE,multi_draw}. While the extension |
|
* alone needs only WebGL 1.0, the shader implementation |
|
* relies on uniform buffers, which require WebGL 2.0. |
|
*/ |
|
MultiDraw = UniformBuffers|(1 << 5) |
|
}; |
|
|
|
/** |
|
* @brief Flags |
|
* |
|
* @see @ref flags(), @ref Configuration::setFlags() |
|
*/ |
|
typedef Containers::EnumSet<Flag> Flags; |
|
#else |
|
/* Done this way to be prepared for possible future diversion of 2D |
|
and 3D flags (e.g. introducing 3D-specific features) */ |
|
typedef Implementation::LineGLFlag Flag; |
|
typedef Implementation::LineGLFlags Flags; |
|
#endif |
|
|
|
/** |
|
* @brief Compile asynchronously |
|
* |
|
* Compared to @ref LineGL(const Configuration&) can perform an |
|
* asynchronous compilation and linking. See @ref shaders-async for |
|
* more information. |
|
* @see @ref LineGL(CompileState&&) |
|
*/ |
|
/* Compared to the non-templated shaders like PhongGL or |
|
MeshVisualizerGL2D using a forward declaration is fine here. Huh. */ |
|
static CompileState compile(const Configuration& configuration = Configuration{}); |
|
|
|
/** @brief Constructor */ |
|
/* Compared to the non-templated shaders like PhongGL or |
|
MeshVisualizerGL2D using a forward declaration is fine here. Huh. */ |
|
explicit LineGL(const Configuration& configuration = Configuration{}); |
|
|
|
/** |
|
* @brief Finalize an asynchronous compilation |
|
* |
|
* Takes an asynchronous compilation state returned by @ref compile() |
|
* and forms a ready-to-use shader object. See @ref shaders-async for |
|
* more information. |
|
*/ |
|
explicit LineGL(CompileState&& state); |
|
|
|
/** |
|
* @brief Construct without creating the underlying OpenGL object |
|
* |
|
* The constructed instance is equivalent to a moved-from state. Useful |
|
* in cases where you will overwrite the instance later anyway. Move |
|
* another object over it to make it useful. |
|
* |
|
* This function can be safely used for constructing (and later |
|
* destructing) objects even without any OpenGL context being active. |
|
* However note that this is a low-level and a potentially dangerous |
|
* API, see the documentation of @ref NoCreate for alternatives. |
|
*/ |
|
explicit LineGL(NoCreateT) noexcept: GL::AbstractShaderProgram{NoCreate} {} |
|
|
|
/** @brief Copying is not allowed */ |
|
LineGL(const LineGL<dimensions>&) = delete; |
|
|
|
/** @brief Move constructor */ |
|
LineGL(LineGL<dimensions>&&) noexcept = default; |
|
|
|
/** @brief Copying is not allowed */ |
|
LineGL<dimensions>& operator=(const LineGL<dimensions>&) = delete; |
|
|
|
/** @brief Move assignment */ |
|
LineGL<dimensions>& operator=(LineGL<dimensions>&&) noexcept = default; |
|
|
|
/** |
|
* @brief Flags |
|
* |
|
* @see @ref Configuration::setFlags() |
|
*/ |
|
Flags flags() const { return _flags; } |
|
|
|
/** |
|
* @brief Cap style |
|
* |
|
* @see @ref Configuration::setCapStyle() |
|
*/ |
|
LineCapStyle capStyle() const { return _capStyle; } |
|
|
|
/** |
|
* @brief Join style |
|
* |
|
* @see @ref Configuration::setJoinStyle() |
|
*/ |
|
LineJoinStyle joinStyle() const { return _joinStyle; } |
|
|
|
/** |
|
* @brief Material count |
|
* |
|
* Statically defined size of the @ref LineMaterialUniform uniform |
|
* buffer bound with @ref bindMaterialBuffer(). Has use only if |
|
* @ref Flag::UniformBuffers is set and @ref Flag::ShaderStorageBuffers |
|
* is not set. |
|
* @see @ref Configuration::setMaterialCount() |
|
*/ |
|
UnsignedInt materialCount() const { return _materialCount; } |
|
|
|
/** |
|
* @brief Draw count |
|
* |
|
* Statically defined size of each of the |
|
* @ref TransformationProjectionUniform2D / |
|
* @ref TransformationProjectionUniform3D and @ref LineDrawUniform |
|
* uniform buffers bound with @ref bindTransformationProjectionBuffer() |
|
* and @ref bindDrawBuffer(). Has use only if @ref Flag::UniformBuffers |
|
* is set and @ref Flag::ShaderStorageBuffers is not set. |
|
* @see @ref Configuration::setDrawCount() |
|
*/ |
|
UnsignedInt drawCount() const { return _drawCount; } |
|
|
|
/** |
|
* @brief Set viewport size |
|
* @return Reference to self (for method chaining) |
|
* |
|
* Line width and smoothness set in either @ref setWidth() / |
|
* @ref setSmoothness() or @ref LineMaterialUniform::width / |
|
* @ref LineMaterialUniform::smoothness depends on this value --- i.e., |
|
* a value of @cpp 1.0f @ce is one pixel only if @ref setViewportSize() |
|
* is called with the actual pixel size of the viewport. Initial value |
|
* is a zero vector. |
|
*/ |
|
LineGL<dimensions>& setViewportSize(const Vector2& size); |
|
|
|
/** @{ |
|
* @name Uniform setters |
|
* |
|
* Used only if @ref Flag::UniformBuffers is not set. |
|
*/ |
|
|
|
/** |
|
* @brief Set transformation and projection matrix |
|
* @return Reference to self (for method chaining) |
|
* |
|
* Initial value is an identity matrix. If |
|
* @ref Flag::InstancedTransformation is set, the per-instance |
|
* transformation matrix coming from the @ref TransformationMatrix |
|
* attribute is applied first, before this one. |
|
* |
|
* Expects that @ref Flag::UniformBuffers is not set, in that case fill |
|
* @ref TransformationProjectionUniform2D::transformationProjectionMatrix / |
|
* @ref TransformationProjectionUniform3D::transformationProjectionMatrix |
|
* and call @ref bindTransformationProjectionBuffer() instead. |
|
*/ |
|
LineGL<dimensions>& setTransformationProjectionMatrix(const MatrixTypeFor<dimensions, Float>& matrix); |
|
|
|
/** |
|
* @brief Set background color |
|
* @return Reference to self (for method chaining) |
|
* |
|
* Initial value is @cpp 0x00000000_rgbaf @ce. Used for edge smoothing |
|
* if smoothness is non-zero, and for background areas if |
|
* @ref LineCapStyle::Round or @ref LineCapStyle::Triangle is used. If |
|
* smoothness is zero and @ref LineCapStyle::Butt or |
|
* @ref LineCapStyle::Square is used, only the foreground color is |
|
* used. |
|
* |
|
* Expects that @ref Flag::UniformBuffers is not set, in that case fill |
|
* @ref LineMaterialUniform::backgroundColor and call |
|
* @ref bindMaterialBuffer() instead. |
|
* @see @ref setColor(), @ref setSmoothness(), |
|
* @ref Configuration::setCapStyle() |
|
*/ |
|
LineGL<dimensions>& setBackgroundColor(const Magnum::Color4& color); |
|
|
|
/** |
|
* @brief Set color |
|
* @return Reference to self (for method chaining) |
|
* |
|
* Initial value is @cpp 0xffffffff_rgbaf @ce. |
|
* |
|
* Expects that @ref Flag::UniformBuffers is not set, in that case fill |
|
* @ref LineMaterialUniform::color and call @ref bindMaterialBuffer() |
|
* instead. |
|
* @see @ref setBackgroundColor() |
|
*/ |
|
LineGL<dimensions>& setColor(const Magnum::Color4& color); |
|
|
|
/** |
|
* @brief Set line width |
|
* @return Reference to self (for method chaining) |
|
* |
|
* Screen-space, interpreted depending on the viewport size --- i.e., |
|
* a value of @cpp 1.0f @ce is one pixel only if @ref setViewportSize() |
|
* is called with the actual pixel size of the viewport. Initial value |
|
* is @cpp 1.0f @ce. |
|
* |
|
* Expects that @ref Flag::UniformBuffers is not set, in that case fill |
|
* @ref LineMaterialUniform::width and call @ref bindMaterialBuffer() |
|
* instead. |
|
*/ |
|
LineGL<dimensions>& setWidth(Float width); |
|
|
|
/** |
|
* @brief Set line smoothness |
|
* @return Reference to self (for method chaining) |
|
* |
|
* Larger values will make edges look less aliased (but blurry), |
|
* smaller values will make them more crisp (but possibly aliased). |
|
* Screen-space, interpreted depending on the viewport size --- i.e., |
|
* a value of @cpp 1.0f @ce is one pixel only if @ref setViewportSize() |
|
* is called with the actual pixel size of the viewport. Initial value |
|
* is @cpp 0.0f @ce. |
|
* |
|
* Expects that @ref Flag::UniformBuffers is not set, in that case fill |
|
* @ref LineMaterialUniform::smoothness and call @ref bindMaterialBuffer() |
|
* instead. |
|
*/ |
|
LineGL<dimensions>& setSmoothness(Float smoothness); |
|
|
|
/** |
|
* @brief Set miter length limit |
|
* @return Reference to self (for method chaining) |
|
* |
|
* Maximum length (relative to line width) over which a |
|
* @ref LineJoinStyle::Miter join is converted to a |
|
* @ref LineJoinStyle::Bevel in order to avoid sharp corners extending |
|
* too much. Default value is @cpp 4.0f @ce, which corresponds to |
|
* approximately 29 degrees. Alternatively you can set the limit as an |
|
* angle using @ref setMiterAngleLimit(). Miter length is calculated |
|
* using the following formula, where @f$ w @f$ is line half-width, |
|
* @f$ l @f$ is miter length and @f$ \theta @f$ is angle between two |
|
* line segments: @f[ |
|
* \frac{w}{l} = \sin(\frac{\theta}{2}) |
|
* @f] |
|
* |
|
* Expects that @ref joinStyle() is @ref LineJoinStyle::Miter and |
|
* @p limit is greater than or equal to @cpp 1.0f @ce and finite. |
|
* Expects that @ref Flag::UniformBuffers is not set, in that case fill |
|
* @ref LineMaterialUniform::miterLimit using |
|
* @ref LineMaterialUniform::setMiterLengthLimit() and call |
|
* @ref bindMaterialBuffer() instead. |
|
*/ |
|
LineGL<dimensions>& setMiterLengthLimit(Float limit); |
|
|
|
/** |
|
* @brief Set miter angle limit |
|
* @return Reference to self (for method chaining) |
|
* |
|
* Like @ref setMiterLengthLimit(), but specified as a minimum angle |
|
* between two line segments below which a @ref LineJoinStyle::Miter |
|
* join is converted to a @ref LineJoinStyle::Bevel in order to avoid |
|
* sharp corners extending too much. Default value is approximately |
|
* @cpp 28.955_degf @ce, see @ref setMiterLengthLimit() above for more |
|
* information. |
|
* |
|
* Expects that @ref joinStyle() is @ref LineJoinStyle::Miter and |
|
* @p limit is greater than @cpp 0.0_radf @ce. Expects that |
|
* @ref Flag::UniformBuffers is not set, in that case fill |
|
* @ref LineMaterialUniform::miterLimit using |
|
* @ref LineMaterialUniform::setMiterAngleLimit() and call |
|
* @ref bindMaterialBuffer() instead. |
|
*/ |
|
LineGL<dimensions>& setMiterAngleLimit(Rad limit); |
|
|
|
/** |
|
* @brief Set object ID |
|
* @return Reference to self (for method chaining) |
|
* |
|
* Expects that the shader was created with @ref Flag::ObjectId |
|
* enabled. Value set here is written to the @ref ObjectIdOutput, see |
|
* @ref Shaders-LineGL-object-id for more information. Initial value |
|
* is @cpp 0 @ce. If @ref Flag::InstancedObjectId is enabled as well, |
|
* this value is added to the ID coming from the @ref ObjectId |
|
* attribute. |
|
* |
|
* Expects that @ref Flag::UniformBuffers is not set, in that case fill |
|
* @ref LineDrawUniform::objectId and call @ref bindDrawBuffer() |
|
* instead. |
|
*/ |
|
LineGL<dimensions>& setObjectId(UnsignedInt id); |
|
|
|
/** |
|
* @} |
|
*/ |
|
|
|
/** @{ |
|
* @name Uniform / shader storage buffer binding and related uniform setters |
|
* |
|
* Used if @ref Flag::UniformBuffers is set. |
|
*/ |
|
|
|
/** |
|
* @brief Bind a draw offset |
|
* @return Reference to self (for method chaining) |
|
* |
|
* Specifies which item in the @ref TransformationProjectionUniform2D / |
|
* @ref TransformationProjectionUniform3D and @ref LineDrawUniform |
|
* buffers bound with @ref bindTransformationProjectionBuffer() and |
|
* @ref bindDrawBuffer() should be used for current draw. Expects that |
|
* @ref Flag::UniformBuffers is set and @p offset is less than |
|
* @ref drawCount(). Initial value is @cpp 0 @ce, if @ref drawCount() |
|
* is @cpp 1 @ce, the function is a no-op as the shader assumes draw |
|
* offset to be always zero. |
|
* |
|
* If @ref Flag::MultiDraw is set, @glsl gl_DrawID @ce is added to this |
|
* value, which makes each draw submitted via |
|
* @ref GL::AbstractShaderProgram::draw(const Containers::Iterable<MeshView>&) |
|
* pick up its own per-draw parameters. |
|
* @requires_gl31 Extension @gl_extension{ARB,uniform_buffer_object} |
|
* @requires_gles30 Uniform buffers are not available in OpenGL ES 2.0. |
|
* @requires_webgl20 Uniform buffers are not available in WebGL 1.0. |
|
*/ |
|
LineGL<dimensions>& setDrawOffset(UnsignedInt offset); |
|
|
|
/** |
|
* @brief Bind a transformation and projection uniform / shader storage buffer |
|
* @return Reference to self (for method chaining) |
|
* |
|
* Expects that @ref Flag::UniformBuffers is set. The buffer is |
|
* expected to contain @ref drawCount() instances of |
|
* @ref TransformationProjectionUniform2D / |
|
* @ref TransformationProjectionUniform3D. At the very least you need |
|
* to call also @ref bindDrawBuffer() and @ref bindMaterialBuffer(). |
|
* @requires_gl31 Extension @gl_extension{ARB,uniform_buffer_object} |
|
*/ |
|
LineGL<dimensions>& bindTransformationProjectionBuffer(GL::Buffer& buffer); |
|
LineGL<dimensions>& bindTransformationProjectionBuffer(GL::Buffer& buffer, GLintptr offset, GLsizeiptr size); /**< @overload */ |
|
|
|
/** |
|
* @brief Bind a draw uniform / shader storage buffer |
|
* @return Reference to self (for method chaining) |
|
* |
|
* Expects that @ref Flag::UniformBuffers is set. The buffer is |
|
* expected to contain @ref drawCount() instances of |
|
* @ref LineDrawUniform. At the very least you need to call also |
|
* @ref bindTransformationProjectionBuffer() and |
|
* @ref bindMaterialBuffer(). |
|
* @requires_gl31 Extension @gl_extension{ARB,uniform_buffer_object} |
|
*/ |
|
LineGL<dimensions>& bindDrawBuffer(GL::Buffer& buffer); |
|
LineGL<dimensions>& bindDrawBuffer(GL::Buffer& buffer, GLintptr offset, GLsizeiptr size); /**< @overload */ |
|
|
|
/** |
|
* @brief Bind a material uniform / shader storage buffer |
|
* @return Reference to self (for method chaining) |
|
* |
|
* Expects that @ref Flag::UniformBuffers is set. The buffer is |
|
* expected to contain @ref materialCount() instances of |
|
* @ref LineMaterialUniform. At the very least you need to call also |
|
* @ref bindTransformationProjectionBuffer() and @ref bindDrawBuffer(). |
|
* @requires_gl31 Extension @gl_extension{ARB,uniform_buffer_object} |
|
*/ |
|
LineGL<dimensions>& bindMaterialBuffer(GL::Buffer& buffer); |
|
LineGL<dimensions>& bindMaterialBuffer(GL::Buffer& buffer, GLintptr offset, GLsizeiptr size); /**< @overload */ |
|
|
|
/** |
|
* @} |
|
*/ |
|
|
|
MAGNUM_GL_ABSTRACTSHADERPROGRAM_SUBCLASS_DRAW_IMPLEMENTATION(LineGL<dimensions>) |
|
|
|
private: |
|
/* Creates the GL shader program object but does nothing else. |
|
Internal, used by compile(). */ |
|
explicit LineGL(NoInitT); |
|
|
|
Flags _flags; |
|
LineCapStyle _capStyle; |
|
LineJoinStyle _joinStyle; |
|
UnsignedInt _materialCount{}, |
|
_drawCount{}; |
|
Int _viewportSizeUniform{0}, |
|
_transformationProjectionMatrixUniform{1}, |
|
_backgroundColorUniform{2}, |
|
_colorUniform{3}, |
|
_widthUniform{4}, |
|
_smoothnessUniform{5}, |
|
_miterLimitUniform{6}, |
|
_objectIdUniform{7}, |
|
/* Used instead of all other uniforms except viewportSize when |
|
Flag::UniformBuffers is set, so it can alias them */ |
|
_drawOffsetUniform{1}; |
|
}; |
|
|
|
/** |
|
@brief Configuration |
|
|
|
@see @ref LineGL(const Configuration&), @ref compile(const Configuration&) |
|
*/ |
|
template<UnsignedInt dimensions> class MAGNUM_SHADERS_EXPORT LineGL<dimensions>::Configuration { |
|
public: |
|
explicit Configuration(); |
|
|
|
/** @brief Flags */ |
|
Flags flags() const { return _flags; } |
|
|
|
/** |
|
* @brief Set flags |
|
* |
|
* No flags are set by default. |
|
* @see @ref LineGL::flags() |
|
*/ |
|
Configuration& setFlags(Flags flags) { |
|
_flags = flags; |
|
return *this; |
|
} |
|
|
|
/** @brief Cap style */ |
|
LineCapStyle capStyle() const { return _capStyle; } |
|
|
|
/** |
|
* @brief Set cap style |
|
* |
|
* Unlike for example the SVG specification that uses |
|
* @ref LineCapStyle::Butt by default, the default value is |
|
* @ref LineCapStyle::Square, in order to make zero-length lines visible. |
|
* @see @ref LineGL::capStyle() |
|
*/ |
|
Configuration& setCapStyle(LineCapStyle style) { |
|
_capStyle = style; |
|
return *this; |
|
} |
|
|
|
/** @brief Join style */ |
|
LineJoinStyle joinStyle() const { return _joinStyle; } |
|
|
|
/** |
|
* @brief Set join style |
|
* |
|
* Default value is @ref LineJoinStyle::Miter, consistently with the |
|
* SVG specification. |
|
* @see @ref LineGL::joinStyle() |
|
*/ |
|
Configuration& setJoinStyle(LineJoinStyle style) { |
|
_joinStyle = style; |
|
return *this; |
|
} |
|
|
|
/** @brief Material count */ |
|
UnsignedInt materialCount() const { return _materialCount; } |
|
|
|
/** |
|
* @brief Set material count |
|
* |
|
* If @ref Flag::UniformBuffers is set, describes size of a |
|
* @ref LineMaterialUniform buffer bound with |
|
* @ref bindMaterialBuffer(). Uniform buffers have a statically defined |
|
* size and @cpp count*sizeof(LineMaterialUniform) @ce has to be within |
|
* @ref GL::AbstractShaderProgram::maxUniformBlockSize(), if |
|
* @ref Flag::ShaderStorageBuffers is set as well, the buffer is |
|
* unbounded and @p count is ignored. The per-draw materials are |
|
* specified via @ref LineDrawUniform::materialId. Default value is |
|
* @cpp 1 @ce. |
|
* |
|
* If @ref Flag::UniformBuffers isn't set, this value is ignored. |
|
* @see @ref setFlags(), @ref setDrawCount(), |
|
* @ref LineGL::materialCount() |
|
* @requires_gl31 Extension @gl_extension{ARB,uniform_buffer_object} |
|
*/ |
|
Configuration& setMaterialCount(UnsignedInt count) { |
|
_materialCount = count; |
|
return *this; |
|
} |
|
|
|
/** @brief Draw count */ |
|
UnsignedInt drawCount() const { return _drawCount; } |
|
|
|
/** |
|
* @brief Set draw count |
|
* |
|
* If @ref Flag::UniformBuffers is set, describes size of a |
|
* @ref TransformationProjectionUniform2D / |
|
* @ref TransformationProjectionUniform3D / |
|
* @ref LineDrawUniform buffer bound with |
|
* @ref bindTransformationProjectionBuffer() and @ref bindDrawBuffer(). |
|
* Uniform buffers have a statically defined size and the maximum of |
|
* @cpp count*sizeof(TransformationProjectionUniform2D) @ce / |
|
* @cpp count*sizeof(TransformationProjectionUniform3D) @ce and |
|
* @cpp count*sizeof(LineDrawUniform) @ce has to be within |
|
* @ref GL::AbstractShaderProgram::maxUniformBlockSize(), if |
|
* @ref Flag::ShaderStorageBuffers is set as well, the buffers are |
|
* unbounded and @p count is ignored. The draw offset is set via |
|
* @ref setDrawOffset(). Default value is @cpp 1 @ce. |
|
* |
|
* If @ref Flag::UniformBuffers isn't set, this value is ignored. |
|
* @see @ref setFlags(), @ref setMaterialCount(), |
|
* @ref LineGL::drawCount() |
|
* @requires_gl31 Extension @gl_extension{ARB,uniform_buffer_object} |
|
*/ |
|
Configuration& setDrawCount(UnsignedInt count) { |
|
_drawCount = count; |
|
return *this; |
|
} |
|
|
|
private: |
|
Flags _flags; |
|
LineCapStyle _capStyle; |
|
LineJoinStyle _joinStyle; |
|
UnsignedInt _materialCount{1}; |
|
UnsignedInt _drawCount{1}; |
|
}; |
|
|
|
/** |
|
@brief Asynchronous compilation state |
|
|
|
Returned by @ref compile(). See @ref shaders-async for more information. |
|
*/ |
|
template<UnsignedInt dimensions> class LineGL<dimensions>::CompileState: public LineGL<dimensions> { |
|
/* Everything deliberately private except for the inheritance */ |
|
friend class LineGL; |
|
|
|
explicit CompileState(NoCreateT): LineGL{NoCreate}, _vert{NoCreate}, _frag{NoCreate} {} |
|
|
|
explicit CompileState(LineGL<dimensions>&& shader, GL::Shader&& vert, GL::Shader&& frag |
|
#if !defined(MAGNUM_TARGET_GLES) || !defined(MAGNUM_TARGET_WEBGL) |
|
, GL::Version version |
|
#endif |
|
): LineGL<dimensions>{Utility::move(shader)}, _vert{Utility::move(vert)}, _frag{Utility::move(frag)} |
|
#if !defined(MAGNUM_TARGET_GLES) || !defined(MAGNUM_TARGET_WEBGL) |
|
, _version{version} |
|
#endif |
|
{} |
|
|
|
Implementation::GLShaderWrapper _vert, _frag; |
|
#if !defined(MAGNUM_TARGET_GLES) || !defined(MAGNUM_TARGET_WEBGL) |
|
GL::Version _version; |
|
#endif |
|
}; |
|
|
|
/** |
|
@brief 2D line OpenGL shader |
|
@m_since_latest |
|
*/ |
|
typedef LineGL<2> LineGL2D; |
|
|
|
/** |
|
@brief 3D LineGL OpenGL shader |
|
@m_since_latest |
|
*/ |
|
typedef LineGL<3> LineGL3D; |
|
|
|
#ifdef DOXYGEN_GENERATING_OUTPUT |
|
/** |
|
* @debugoperatorclassenum{LineGL,LineGL::Flag} |
|
* @m_since_latest |
|
*/ |
|
template<UnsignedInt dimensions> Debug& operator<<(Debug& debug, LineGL<dimensions>::Flag value); |
|
|
|
/** |
|
* @debugoperatorclassenum{LineGL,LineGL::Flags} |
|
* @m_since_latest |
|
*/ |
|
template<UnsignedInt dimensions> Debug& operator<<(Debug& debug, LineGL<dimensions>::Flags value); |
|
#else |
|
namespace Implementation { |
|
MAGNUM_SHADERS_EXPORT Debug& operator<<(Debug& debug, LineGLFlag value); |
|
MAGNUM_SHADERS_EXPORT Debug& operator<<(Debug& debug, LineGLFlags value); |
|
} |
|
#endif |
|
|
|
}} |
|
#else |
|
#error this header is not available in the OpenGL ES 2.0 / WebGL 1.0 build |
|
#endif |
|
|
|
#endif
|
|
|