#include <Magnum/Shaders/LineGL.h>
template<UnsignedInt dimensions>
LineGL class new in Git master
Line GL shader.
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.
Usage
The shader doesn't work with MeshPrimitive::
Trade::MeshData circle = Primitives::circle2DWireframe(16); GL::Mesh mesh = MeshTools::compileLines(MeshTools::generateLines(circle));
For rendering use setTransformationProjectionMatrix(), setColor(), setWidth() and others. It's important to pass viewport size in setViewportSize() as the line width is interpreted relative to it.
Shaders::LineGL2D shader; shader .setViewportSize(Vector2{GL::defaultFramebuffer.viewport().size()}) .setTransformationProjectionMatrix(projectionMatrix*transformationMatrix) .setColor(0x2f83cc_rgbf) .setWidth(4.0f) .draw(mesh);
Line triangulation
Each line segment is rendered as a quad consisting of two triangles. Standalone segments have cap style configurable via Configuration::
Joins between consecutive segments in contiguous line strips are expanded to form a gap-less mesh without overlaps. Depending on join style picked in Configuration::A
, B
and C
may be filled with another triangle:
Antialiasing
The lines aren't smoothed out by default, use 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 setBackgroundColor() to a color matching the background and keep blending disabled, but note that you may get artifacts if the lines are self-overlapping.
GL::Renderer::enable(GL::Renderer::Feature::Blending); GL::Renderer::setBlendFunction( GL::Renderer::BlendFunction::One, GL::Renderer::BlendFunction::OneMinusSourceAlpha); Shaders::LineGL2D shader; shader … .setSmoothness(1.0f) .draw(mesh);
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.
Object ID output
The shader supports writing object ID to the framebuffer for object picking or other annotation purposes. Enable it using Flag::
The functionality is practically the same as in the FlatGL shader, see 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 LineCapStyle::
Instanced rendering
Enabling Flag::
Uniform buffers
See Using uniform buffers 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 TransformationProjectionUniform2D / TransformationProjectionUniform3D buffer bound with bindTransformationProjectionBuffer(). To maximize use of the limited uniform buffer memory, materials are supplied separately in a LineMaterialUniform buffer bound with bindMaterialBuffer() and then referenced via materialId from a LineDrawUniform bound with bindDrawBuffer(). A uniform buffer setup equivalent to the snippet at the top would look like this — note that setViewportSize() is an immediate uniform here as well, as it's assumed to be set globally and rarely changed:
GL::Buffer transformationProjectionUniform, materialUniform, drawUniform; transformationProjectionUniform.setData({ Shaders::TransformationProjectionUniform2D{} .setTransformationProjectionMatrix(projectionMatrix*transformationMatrix) }); materialUniform.setData({ Shaders::LineMaterialUniform{} .setColor(0x2f83cc_rgbf) }); drawUniform.setData({ Shaders::LineDrawUniform{} .setMaterialId(0) }); Shaders::LineGL2D shader{Shaders::LineGL2D::Configuration{} .setFlags(Shaders::LineGL2D::Flag::UniformBuffers)}; shader .setViewportSize(Vector2{GL::defaultFramebuffer.viewport().size()}) .bindTransformationProjectionBuffer(transformationProjectionUniform) .bindMaterialBuffer(materialUniform) .bindDrawBuffer(drawUniform) .draw(mesh);
For a multidraw workflow enable Flag::
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.
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 blue 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 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 — {0, 1, 2, 2, 1, 3, …}
.
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:
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 azure point would appear above the green one instead of below. Thus the index buffer needs to handle both cases — {…, 2, 3, 4, 4, 3, 5, …}
— and one of them always denegerates to a zero-area triangle.
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 PreviousPosition and a 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.
What's left is giving the shader an ability to distinguish the direction in which to expand the point (LineVertexAnnotation::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.
Overlapping layouts with less data redundancy
Assuming a 3D line mesh with floating-point position attributes, the Annotation attribute packed into a single byte and MeshIndexType::
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.
Standalone line segments without joins
If the mesh consists just of loose line segments and no joints need to be drawn, the Position attribute can be bound with an offset of -2
elements to the PreviousPosition and +2
elements to the 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 bytes, which is roughly the same amount of data as for loose CPU-side-generated indexed quads, and ~2.7x as much as bytes a sufficiently large (non-indexed) MeshPrimitive::
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 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 -4
elements to the PreviousPosition and +4
elements to the NextPosition.
This needs only one triangle in the index buffer for each join instead of two and has a memory requirement of bytes, with being the line strip count. With a mesh consisting of just a single strip this is bytes, which is ~1.8x as much as CPU-side-generated indexed quads and ~6.3x as much as a MeshPrimitive::
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 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 -3
elements to the PreviousPosition and +3
elements to the NextPosition.
This has a memory requirement of bytes. With a mesh consisting of just a single strip this is bytes, which is ~1.4x as much as CPU-side-generated indexed quads and ~4.75x as much as a MeshPrimitive::
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 LineJoinStyle::
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 Position attribute between contiguous line strips, and it's bound with an offset of -2
elements to the PreviousPosition and +2
elements to the NextPosition.
The memory requirement is bytes. With a mesh consisting of a single strip it's bytes. This is roughly the same memory use as bytes for CPU-side-generated quads with miter joins only, and ~3.2x as much as a MeshPrimitive::
Base classes
- class Magnum::GL::AbstractShaderProgram
- Base for shader program implementations.
Derived classes
- class Magnum::Shaders::LineGL::CompileState
- Asynchronous compilation state.
Public types
- class CompileState
- Asynchronous compilation state.
- class Configuration
- Configuration.
- enum (anonymous): UnsignedInt { ColorOutput = GenericGL<dimensions>::ColorOutput, ObjectIdOutput = GenericGL<dimensions>::ObjectIdOutput }
- enum class Flag: UnsignedShort { VertexColor = 1 << 0, ObjectId = 1 << 1, InstancedObjectId = (1 << 2)|ObjectId, InstancedTransformation = 1 << 3, UniformBuffers = 1 << 4, ShaderStorageBuffers = UniformBuffers|(1 << 6) new in Git master, MultiDraw = UniformBuffers|(1 << 5) }
- Flag.
- using Position = GenericGL<dimensions>::Position
- Vertex position.
-
using PreviousPosition = GL::
Attribute<3, VectorTypeFor<dimensions, Float>> - Previous position.
-
using NextPosition = GL::
Attribute<5, VectorTypeFor<dimensions, Float>> - Next position.
-
using Annotation = GL::
Attribute<1, UnsignedInt> - Vertex annotation.
- using Color3 = GenericGL<dimensions>::Color3
- Three-component vertex color.
- using Color4 = GenericGL<dimensions>::Color4
- Four-component vertex color.
- using ObjectId = GenericGL<dimensions>::ObjectId
- (Instanced) object ID
- using TransformationMatrix = GenericGL<dimensions>::TransformationMatrix
- (Instanced) transformation matrix
-
using Flags = Containers::
EnumSet<Flag> - Flags.
Public static functions
- static auto compile(const Configuration& configuration = Configuration{}) -> CompileState
- Compile asynchronously.
Constructors, destructors, conversion operators
- LineGL(const Configuration& configuration = Configuration{}) explicit
- Constructor.
- LineGL(CompileState&& state) explicit
- Finalize an asynchronous compilation.
- LineGL(NoCreateT) explicit noexcept
- Construct without creating the underlying OpenGL object.
- LineGL(const LineGL<dimensions>&) deleted
- Copying is not allowed.
- LineGL(LineGL<dimensions>&&) defaulted noexcept
- Move constructor.
Public functions
- auto operator=(const LineGL<dimensions>&) -> LineGL<dimensions>& deleted
- Copying is not allowed.
- auto operator=(LineGL<dimensions>&&) -> LineGL<dimensions>& defaulted noexcept
- Move assignment.
- auto flags() const -> Flags
- Flags.
- auto capStyle() const -> LineCapStyle
- Cap style.
- auto joinStyle() const -> LineJoinStyle
- Join style.
- auto materialCount() const -> UnsignedInt
- Material count.
- auto drawCount() const -> UnsignedInt
- Draw count.
- auto setViewportSize(const Vector2& size) -> LineGL<dimensions>&
- Set viewport size.
Uniform setters
Used only if Flag::
- auto setTransformationProjectionMatrix(const MatrixTypeFor<dimensions, Float>& matrix) -> LineGL<dimensions>&
- Set transformation and projection matrix.
-
auto setBackgroundColor(const Magnum::
Color4& color) -> LineGL<dimensions>& - Set background color.
-
auto setColor(const Magnum::
Color4& color) -> LineGL<dimensions>& - Set color.
- auto setWidth(Float width) -> LineGL<dimensions>&
- Set line width.
- auto setSmoothness(Float smoothness) -> LineGL<dimensions>&
- Set line smoothness.
- auto setMiterLengthLimit(Float limit) -> LineGL<dimensions>&
- Set miter length limit.
- auto setMiterAngleLimit(Rad limit) -> LineGL<dimensions>&
- Set miter angle limit.
- auto setObjectId(UnsignedInt id) -> LineGL<dimensions>&
- Set object ID.
Enum documentation
template<UnsignedInt dimensions>
enum Magnum:: Shaders:: LineGL<dimensions>:: (anonymous): UnsignedInt
Enumerators | |
---|---|
ColorOutput |
Color shader output. Present always, expects three- or four-component floating-point or normalized buffer attachment. |
ObjectIdOutput |
Object ID shader output. Generic output, present only if Flag:: |
template<UnsignedInt dimensions>
enum class Magnum:: Shaders:: LineGL<dimensions>:: Flag: UnsignedShort
Flag.
Enumerators | |
---|---|
VertexColor |
Multiply the color with a vertex color. Requires either the Color3 or Color4 attribute to be present. |
ObjectId |
Enable object ID output. See Object ID output for more information. |
InstancedObjectId |
Instanced object ID. Retrieves a per-instance / per-vertex object ID from the ObjectId attribute, outputting a sum of the per-vertex ID and ID coming from setObjectId() or LineDrawUniform:: |
InstancedTransformation |
Instanced transformation. Retrieves a per-instance transformation matrix from the TransformationMatrix attribute and uses it together with the matrix coming from setTransformationProjectionMatrix() or TransformationProjectionUniform2D:: |
UniformBuffers |
Use uniform buffers. Expects that uniform data are supplied via bindTransformationProjectionBuffer(), bindDrawBuffer() and bindMaterialBuffer() instead of direct uniform setters. |
ShaderStorageBuffers new in Git master |
Use shader storage buffers. Superset of functionality provided by Flag:: |
MultiDraw |
Enable multidraw functionality. Implies Flag:: |
Typedef documentation
template<UnsignedInt dimensions>
typedef GenericGL<dimensions>::Position Magnum:: Shaders:: LineGL<dimensions>:: Position
Vertex position.
Generic attribute, Vector2 in 2D, Vector3 in 3D.
template<UnsignedInt dimensions>
typedef GL:: Attribute<3, VectorTypeFor<dimensions, Float>> Magnum:: Shaders:: LineGL<dimensions>:: PreviousPosition
Previous position.
Vector2 in 2D, Vector3 in 3D. Uses the same location as GenericGL::
If LineVertexAnnotation::
template<UnsignedInt dimensions>
typedef GL:: Attribute<5, VectorTypeFor<dimensions, Float>> Magnum:: Shaders:: LineGL<dimensions>:: NextPosition
Next position.
Vector2 in 2D, Vector3 in 3D. Uses the same location as GenericGL::
If LineVertexAnnotation::
template<UnsignedInt dimensions>
typedef GL:: Attribute<1, UnsignedInt> Magnum:: Shaders:: LineGL<dimensions>:: Annotation
Vertex annotation.
Uses the same location as GenericGL::
Contains a set of LineVertexAnnotation bits, see their documentation for more information. The values are guaranteed to fit into 8 bits.
template<UnsignedInt dimensions>
typedef GenericGL<dimensions>::Color3 Magnum:: Shaders:: LineGL<dimensions>:: Color3
Three-component vertex color.
Generic attribute, Magnum::
template<UnsignedInt dimensions>
typedef GenericGL<dimensions>::Color4 Magnum:: Shaders:: LineGL<dimensions>:: Color4
Four-component vertex color.
Generic attribute, Magnum::
template<UnsignedInt dimensions>
typedef GenericGL<dimensions>::ObjectId Magnum:: Shaders:: LineGL<dimensions>:: ObjectId
(Instanced) object ID
Generic attribute, UnsignedInt. Used only if Flag::
template<UnsignedInt dimensions>
typedef GenericGL<dimensions>::TransformationMatrix Magnum:: Shaders:: LineGL<dimensions>:: TransformationMatrix
(Instanced) transformation matrix
Generic attribute, Matrix3 in 2D, Matrix4 in 3D. Used only if Flag::
template<UnsignedInt dimensions>
typedef Containers:: EnumSet<Flag> Magnum:: Shaders:: LineGL<dimensions>:: Flags
Flags.
Function documentation
template<UnsignedInt dimensions>
static CompileState Magnum:: Shaders:: LineGL<dimensions>:: compile(const Configuration& configuration = Configuration{})
Compile asynchronously.
Compared to LineGL(const Configuration&) can perform an asynchronous compilation and linking. See Async shader compilation and linking for more information.
template<UnsignedInt dimensions>
Magnum:: Shaders:: LineGL<dimensions>:: LineGL(CompileState&& state) explicit
Finalize an asynchronous compilation.
Takes an asynchronous compilation state returned by compile() and forms a ready-to-use shader object. See Async shader compilation and linking for more information.
template<UnsignedInt dimensions>
Magnum:: Shaders:: LineGL<dimensions>:: LineGL(NoCreateT) explicit noexcept
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 NoCreate for alternatives.
template<UnsignedInt dimensions>
Flags Magnum:: Shaders:: LineGL<dimensions>:: flags() const
Flags.
template<UnsignedInt dimensions>
LineCapStyle Magnum:: Shaders:: LineGL<dimensions>:: capStyle() const
Cap style.
template<UnsignedInt dimensions>
LineJoinStyle Magnum:: Shaders:: LineGL<dimensions>:: joinStyle() const
Join style.
template<UnsignedInt dimensions>
UnsignedInt Magnum:: Shaders:: LineGL<dimensions>:: materialCount() const
Material count.
Statically defined size of the LineMaterialUniform uniform buffer bound with bindMaterialBuffer(). Has use only if Flag::
template<UnsignedInt dimensions>
UnsignedInt Magnum:: Shaders:: LineGL<dimensions>:: drawCount() const
Draw count.
Statically defined size of each of the TransformationProjectionUniform2D / TransformationProjectionUniform3D and LineDrawUniform uniform buffers bound with bindTransformationProjectionBuffer() and bindDrawBuffer(). Has use only if Flag::
template<UnsignedInt dimensions>
LineGL<dimensions>& Magnum:: Shaders:: LineGL<dimensions>:: setViewportSize(const Vector2& size)
Set viewport size.
Returns | Reference to self (for method chaining) |
---|
Line width and smoothness set in either setWidth() / setSmoothness() or LineMaterialUniform::1.0f
is one pixel only if setViewportSize() is called with the actual pixel size of the viewport. Initial value is a zero vector.
template<UnsignedInt dimensions>
LineGL<dimensions>& Magnum:: Shaders:: LineGL<dimensions>:: setTransformationProjectionMatrix(const MatrixTypeFor<dimensions, Float>& matrix)
Set transformation and projection matrix.
Returns | Reference to self (for method chaining) |
---|
Initial value is an identity matrix. If Flag::
Expects that Flag::
template<UnsignedInt dimensions>
LineGL<dimensions>& Magnum:: Shaders:: LineGL<dimensions>:: setBackgroundColor(const Magnum:: Color4& color)
Set background color.
Returns | Reference to self (for method chaining) |
---|
Initial value is 0x00000000_rgbaf
. Used for edge smoothing if smoothness is non-zero, and for background areas if LineCapStyle::
Expects that Flag::
template<UnsignedInt dimensions>
LineGL<dimensions>& Magnum:: Shaders:: LineGL<dimensions>:: setColor(const Magnum:: Color4& color)
Set color.
Returns | Reference to self (for method chaining) |
---|
Initial value is 0xffffffff_rgbaf
.
Expects that Flag::
template<UnsignedInt dimensions>
LineGL<dimensions>& Magnum:: Shaders:: LineGL<dimensions>:: setWidth(Float width)
Set line width.
Returns | Reference to self (for method chaining) |
---|
Screen-space, interpreted depending on the viewport size — i.e., a value of 1.0f
is one pixel only if setViewportSize() is called with the actual pixel size of the viewport. Initial value is 1.0f
.
Expects that Flag::
template<UnsignedInt dimensions>
LineGL<dimensions>& Magnum:: Shaders:: LineGL<dimensions>:: setSmoothness(Float smoothness)
Set line smoothness.
Returns | 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 1.0f
is one pixel only if setViewportSize() is called with the actual pixel size of the viewport. Initial value is 0.0f
.
Expects that Flag::
template<UnsignedInt dimensions>
LineGL<dimensions>& Magnum:: Shaders:: LineGL<dimensions>:: setMiterLengthLimit(Float limit)
Set miter length limit.
Returns | Reference to self (for method chaining) |
---|
Maximum length (relative to line width) over which a LineJoinStyle::4.0f
, which corresponds to approximately 29 degrees. Alternatively you can set the limit as an angle using setMiterAngleLimit(). Miter length is calculated using the following formula, where is line half-width, is miter length and is angle between two line segments:
Expects that joinStyle() is LineJoinStyle::limit
is greater than or equal to 1.0f
and finite. Expects that Flag::
template<UnsignedInt dimensions>
LineGL<dimensions>& Magnum:: Shaders:: LineGL<dimensions>:: setMiterAngleLimit(Rad limit)
Set miter angle limit.
Returns | Reference to self (for method chaining) |
---|
Like setMiterLengthLimit(), but specified as a minimum angle between two line segments below which a LineJoinStyle::28.955_degf
, see setMiterLengthLimit() above for more information.
Expects that joinStyle() is LineJoinStyle::limit
is greater than 0.0_radf
. Expects that Flag::
template<UnsignedInt dimensions>
LineGL<dimensions>& Magnum:: Shaders:: LineGL<dimensions>:: setObjectId(UnsignedInt id)
Set object ID.
Returns | Reference to self (for method chaining) |
---|
Expects that the shader was created with Flag::0
. If Flag::
Expects that Flag::
template<UnsignedInt dimensions>
LineGL<dimensions>& Magnum:: Shaders:: LineGL<dimensions>:: setDrawOffset(UnsignedInt offset)
Bind a draw offset.
Returns | Reference to self (for method chaining) |
---|
Specifies which item in the TransformationProjectionUniform2D / TransformationProjectionUniform3D and LineDrawUniform buffers bound with bindTransformationProjectionBuffer() and bindDrawBuffer() should be used for current draw. Expects that Flag::offset
is less than drawCount(). Initial value is 0
, if drawCount() is 1
, the function is a no-op as the shader assumes draw offset to be always zero.
If Flag::gl_DrawID
is added to this value, which makes each draw submitted via GL::
template<UnsignedInt dimensions>
LineGL<dimensions>& Magnum:: Shaders:: LineGL<dimensions>:: bindTransformationProjectionBuffer(GL:: Buffer& buffer)
Bind a transformation and projection uniform / shader storage buffer.
Returns | Reference to self (for method chaining) |
---|
Expects that Flag::
template<UnsignedInt dimensions>
LineGL<dimensions>& Magnum:: Shaders:: LineGL<dimensions>:: bindTransformationProjectionBuffer(GL:: Buffer& buffer,
GLintptr offset,
GLsizeiptr size)
This is an overloaded member function, provided for convenience. It differs from the above function only in what argument(s) it accepts.
template<UnsignedInt dimensions>
LineGL<dimensions>& Magnum:: Shaders:: LineGL<dimensions>:: bindDrawBuffer(GL:: Buffer& buffer)
Bind a draw uniform / shader storage buffer.
Returns | Reference to self (for method chaining) |
---|
Expects that Flag::
template<UnsignedInt dimensions>
LineGL<dimensions>& Magnum:: Shaders:: LineGL<dimensions>:: bindDrawBuffer(GL:: Buffer& buffer,
GLintptr offset,
GLsizeiptr size)
This is an overloaded member function, provided for convenience. It differs from the above function only in what argument(s) it accepts.
template<UnsignedInt dimensions>
LineGL<dimensions>& Magnum:: Shaders:: LineGL<dimensions>:: bindMaterialBuffer(GL:: Buffer& buffer)
Bind a material uniform / shader storage buffer.
Returns | Reference to self (for method chaining) |
---|
Expects that Flag::
template<UnsignedInt dimensions>
LineGL<dimensions>& Magnum:: Shaders:: LineGL<dimensions>:: bindMaterialBuffer(GL:: Buffer& buffer,
GLintptr offset,
GLsizeiptr size)
This is an overloaded member function, provided for convenience. It differs from the above function only in what argument(s) it accepts.
template<UnsignedInt dimensions>
template<UnsignedInt dimensions>
Debug& operator<<(Debug& debug,
LineGL<dimensions>::Flag value) new in Git master
Debug output operator.
template<UnsignedInt dimensions>
template<UnsignedInt dimensions>
Debug& operator<<(Debug& debug,
LineGL<dimensions>::Flags value) new in Git master
Debug output operator.