mirror of https://github.com/mosra/magnum.git
Browse Source
TODO: rework this against MeshTools first TODO: tests for edge cases (zero-size lines, angles causing infinite corners, ...), OTOH the defaults test doesn't have to be so complex TODO: docs TODO: UBOs, multidraw, instancing... TODO: line caps... TODO: ugh the line joints only work if the two segments are ~same length, wtfpull/610/head
13 changed files with 2546 additions and 2 deletions
@ -0,0 +1,202 @@
|
||||
/* |
||||
This file is part of Magnum. |
||||
|
||||
Copyright © 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019, |
||||
2020, 2021, 2022 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. |
||||
*/ |
||||
|
||||
#if defined(OBJECT_ID) && !defined(GL_ES) && !defined(NEW_GLSL) |
||||
#extension GL_EXT_gpu_shader4: require |
||||
#endif |
||||
|
||||
#ifndef NEW_GLSL |
||||
#define fragmentColor gl_FragColor |
||||
#define in varying |
||||
#endif |
||||
|
||||
#ifndef RUNTIME_CONST |
||||
#define const |
||||
#endif |
||||
|
||||
/* Uniforms */ |
||||
|
||||
#ifdef EXPLICIT_UNIFORM_LOCATION |
||||
layout(location = 2) |
||||
#endif |
||||
uniform mediump float width |
||||
#ifndef GL_ES |
||||
= 1.0 |
||||
#endif |
||||
; |
||||
|
||||
#ifdef EXPLICIT_UNIFORM_LOCATION |
||||
layout(location = 3) |
||||
#endif |
||||
uniform mediump float smoothness |
||||
#ifndef GL_ES |
||||
= 0.0 |
||||
#endif |
||||
; |
||||
|
||||
#ifdef EXPLICIT_UNIFORM_LOCATION |
||||
layout(location = 4) |
||||
#endif |
||||
uniform lowp vec4 backgroundColor |
||||
#ifndef GL_ES |
||||
= vec4(0.0) |
||||
#endif |
||||
; |
||||
|
||||
#ifndef UNIFORM_BUFFERS |
||||
#ifdef EXPLICIT_UNIFORM_LOCATION |
||||
layout(location = 5) |
||||
#endif |
||||
uniform lowp vec4 color |
||||
#ifndef GL_ES |
||||
= vec4(1.0) |
||||
#endif |
||||
; |
||||
|
||||
#ifdef OBJECT_ID |
||||
#ifdef EXPLICIT_UNIFORM_LOCATION |
||||
layout(location = 6) |
||||
#endif |
||||
/* mediump is just 2^10, which might not be enough, this is 2^16 */ |
||||
uniform highp uint objectId; /* defaults to zero */ |
||||
#endif |
||||
|
||||
/* Uniform buffers */ |
||||
|
||||
#else |
||||
#ifndef MULTI_DRAW |
||||
#if DRAW_COUNT > 1 |
||||
#ifdef EXPLICIT_UNIFORM_LOCATION |
||||
layout(location = 0) |
||||
#endif |
||||
uniform highp uint drawOffset |
||||
#ifndef GL_ES |
||||
= 0u |
||||
#endif |
||||
; |
||||
#else |
||||
#define drawOffset 0u |
||||
#endif |
||||
#define drawId drawOffset |
||||
#endif |
||||
|
||||
struct DrawUniform { |
||||
highp uvec4 materialIdReservedObjectIdReservedReserved; |
||||
#define draw_materialIdReserved materialIdReservedObjectIdReservedReserved.x |
||||
#define draw_objectId materialIdReservedObjectIdReservedReserved.y |
||||
}; |
||||
|
||||
layout(std140 |
||||
#ifdef EXPLICIT_BINDING |
||||
, binding = 2 |
||||
#endif |
||||
) uniform Draw { |
||||
DrawUniform draws[DRAW_COUNT]; |
||||
}; |
||||
|
||||
struct MaterialUniform { |
||||
lowp vec4 color; |
||||
}; |
||||
|
||||
layout(std140 |
||||
#ifdef EXPLICIT_BINDING |
||||
, binding = 4 |
||||
#endif |
||||
) uniform Material { |
||||
MaterialUniform materials[MATERIAL_COUNT]; |
||||
}; |
||||
#endif |
||||
|
||||
/* Inputs */ |
||||
|
||||
in highp vec2 centerDistanceSigned; |
||||
in highp float halfSegmentLength; |
||||
|
||||
#ifdef VERTEX_COLOR |
||||
in lowp vec4 interpolatedVertexColor; |
||||
#endif |
||||
|
||||
#ifdef INSTANCED_OBJECT_ID |
||||
flat in highp uint interpolatedInstanceObjectId; |
||||
#endif |
||||
|
||||
/* Outputs */ |
||||
|
||||
#ifdef NEW_GLSL |
||||
#ifdef EXPLICIT_ATTRIB_LOCATION |
||||
layout(location = COLOR_OUTPUT_ATTRIBUTE_LOCATION) |
||||
#endif |
||||
out lowp vec4 fragmentColor; |
||||
#endif |
||||
#ifdef OBJECT_ID |
||||
#ifdef EXPLICIT_ATTRIB_LOCATION |
||||
layout(location = OBJECT_ID_OUTPUT_ATTRIBUTE_LOCATION) |
||||
#endif |
||||
/* mediump is just 2^10, which might not be enough, this is 2^16 */ |
||||
out highp uint fragmentObjectId; |
||||
#endif |
||||
|
||||
#ifdef MULTI_DRAW |
||||
flat in highp uint drawId; |
||||
#endif |
||||
|
||||
void main() { |
||||
#ifdef UNIFORM_BUFFERS |
||||
#ifdef OBJECT_ID |
||||
highp const uint objectId = draws[drawId].draw_objectId; |
||||
#endif |
||||
#if MATERIAL_COUNT > 1 |
||||
mediump const uint materialId = draws[drawId].draw_materialIdReserved & 0xffffu; |
||||
#else |
||||
#define materialId 0u |
||||
#endif |
||||
lowp const vec4 color = materials[materialId].color; |
||||
#endif |
||||
|
||||
/* Pixels with `abs(centerDistanceSigned) <= [d+w,w]` are foreground, |
||||
pixels with `abs(centerDistanceSigned) > [d+w+s,w+s]` are background, |
||||
smoothstep in between */ |
||||
highp const vec2 edge = vec2(halfSegmentLength+0.5*width, width*0.5); |
||||
lowp const vec2 factor = smoothstep( // TODO CSE |
||||
edge - vec2(smoothness), |
||||
edge + vec2(smoothness), abs(centerDistanceSigned)); |
||||
// lowp const vec2 factor = step(edge, abs(centerDistanceSigned)); |
||||
|
||||
// fragmentColor.ba = vec2(0.0); |
||||
fragmentColor = mix( |
||||
#ifdef VERTEX_COLOR |
||||
interpolatedVertexColor* |
||||
#endif |
||||
color, backgroundColor, max(factor.x, factor.y)); // TODO huh*/ |
||||
|
||||
#ifdef OBJECT_ID |
||||
// TODO how to handle smoothness here? |
||||
fragmentObjectId = all(lessThan(abs(centerDistanceSigned), edge)) ? |
||||
#ifdef INSTANCED_OBJECT_ID |
||||
interpolatedInstanceObjectId + |
||||
#endif |
||||
objectId : 0u; |
||||
#endif |
||||
} |
||||
@ -0,0 +1,95 @@
|
||||
#ifndef Magnum_Shaders_Line_h |
||||
#define Magnum_Shaders_Line_h |
||||
/*
|
||||
This file is part of Magnum. |
||||
|
||||
Copyright © 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019, |
||||
2020, 2021, 2022 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. |
||||
*/ |
||||
|
||||
/** @file
|
||||
* @brief Struct @ref Magnum::Shaders::LineDrawUniform, @ref Magnum::Shaders::LineMaterialUniform |
||||
*/ |
||||
|
||||
#include "Magnum/Magnum.h" |
||||
#include "Magnum/Math/Color.h" |
||||
|
||||
namespace Magnum { namespace Shaders { |
||||
|
||||
struct LineDrawUniform { |
||||
/** @brief Construct with default parameters */ |
||||
constexpr explicit LineDrawUniform(DefaultInitT = DefaultInit) noexcept: materialId{0}, objectId{0} {} |
||||
|
||||
/** @brief Construct without initializing the contents */ |
||||
explicit LineDrawUniform(NoInitT) noexcept {} |
||||
|
||||
LineDrawUniform& setMaterialId(UnsignedInt id) { |
||||
materialId = id; |
||||
return *this; |
||||
} |
||||
|
||||
LineDrawUniform& setObjectId(UnsignedInt id) { |
||||
objectId = id; |
||||
return *this; |
||||
} |
||||
|
||||
/* This field is an UnsignedInt in the shader and materialId is extracted
|
||||
as (value & 0xffff), so the order has to be different on BE */ |
||||
#ifndef CORRADE_TARGET_BIG_ENDIAN |
||||
alignas(4) UnsignedShort materialId; |
||||
/* warning: Member __pad0__ is not documented. FFS DOXYGEN WHY DO YOU THINK
|
||||
I MADE THOSE UNNAMED, YOU DUMB FOOL */ |
||||
#ifndef DOXYGEN_GENERATING_OUTPUT |
||||
UnsignedShort:16; /* reserved for skinOffset */ |
||||
#endif |
||||
#else |
||||
alignas(4) UnsignedShort:16; /* reserved for skinOffset */ |
||||
UnsignedShort materialId; |
||||
#endif |
||||
|
||||
UnsignedInt objectId; |
||||
|
||||
/* warning: Member __pad1__ is not documented. FFS DOXYGEN WHY DO YOU THINK
|
||||
I MADE THOSE UNNAMED, YOU DUMB FOOL */ |
||||
#ifndef DOXYGEN_GENERATING_OUTPUT |
||||
Int:32; |
||||
Int:32; |
||||
#endif |
||||
}; |
||||
|
||||
struct LineMaterialUniform { |
||||
/** @brief Construct with default parameters */ |
||||
constexpr explicit LineMaterialUniform(DefaultInitT = DefaultInit) noexcept: color{1.0f, 1.0f, 1.0f, 1.0f} {} |
||||
|
||||
/** @brief Construct without initializing the contents */ |
||||
explicit LineMaterialUniform(NoInitT) noexcept: color{NoInit} {} |
||||
|
||||
LineMaterialUniform& setColor(const Color4& color) { |
||||
this->color = color; |
||||
return *this; |
||||
} |
||||
|
||||
Color4 color; |
||||
}; |
||||
|
||||
}} |
||||
|
||||
#endif |
||||
@ -0,0 +1,402 @@
|
||||
/* |
||||
This file is part of Magnum. |
||||
|
||||
Copyright © 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019, |
||||
2020, 2021, 2022 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. |
||||
*/ |
||||
|
||||
#if defined(INSTANCED_OBJECT_ID) && !defined(GL_ES) && !defined(NEW_GLSL) |
||||
#extension GL_EXT_gpu_shader4: require |
||||
#endif |
||||
|
||||
#if defined(UNIFORM_BUFFERS) && defined(TEXTURE_ARRAYS) && !defined(GL_ES) |
||||
#extension GL_ARB_shader_bit_encoding: require |
||||
#endif |
||||
|
||||
#ifdef MULTI_DRAW |
||||
#ifndef GL_ES |
||||
#extension GL_ARB_shader_draw_parameters: require |
||||
#else /* covers WebGL as well */ |
||||
#extension GL_ANGLE_multi_draw: require |
||||
#endif |
||||
#endif |
||||
|
||||
#ifndef NEW_GLSL |
||||
#define in attribute |
||||
#define out varying |
||||
#endif |
||||
|
||||
#ifndef RUNTIME_CONST |
||||
#define const |
||||
#endif |
||||
|
||||
/* Uniforms */ |
||||
|
||||
/* This one is for both classic and UBOs, as it's usually set globally instead |
||||
of changing per-draw */ |
||||
#ifdef EXPLICIT_UNIFORM_LOCATION |
||||
layout(location = 0) |
||||
#endif |
||||
uniform lowp vec2 viewportSize; /* defaults to zero */ |
||||
|
||||
#ifndef UNIFORM_BUFFERS |
||||
#ifdef EXPLICIT_UNIFORM_LOCATION |
||||
layout(location = 1) |
||||
#endif |
||||
#ifdef TWO_DIMENSIONS |
||||
uniform highp mat3 transformationProjectionMatrix |
||||
#ifndef GL_ES |
||||
= mat3(1.0) |
||||
#endif |
||||
; |
||||
#elif defined(THREE_DIMENSIONS) |
||||
uniform highp mat4 transformationProjectionMatrix |
||||
#ifndef GL_ES |
||||
= mat4(1.0) |
||||
#endif |
||||
; |
||||
#else |
||||
#error |
||||
#endif |
||||
|
||||
#ifdef EXPLICIT_UNIFORM_LOCATION |
||||
layout(location = 2) |
||||
#endif |
||||
uniform mediump float width |
||||
#ifndef GL_ES |
||||
= 1.0 |
||||
#endif |
||||
; |
||||
|
||||
#ifdef EXPLICIT_UNIFORM_LOCATION |
||||
layout(location = 3) |
||||
#endif |
||||
uniform mediump float smoothness |
||||
#ifndef GL_ES |
||||
= 0.0 |
||||
#endif |
||||
; |
||||
|
||||
/* Uniform buffers */ |
||||
|
||||
#else |
||||
#if DRAW_COUNT > 1 |
||||
#ifdef EXPLICIT_UNIFORM_LOCATION |
||||
layout(location = 1) |
||||
#endif |
||||
uniform highp uint drawOffset |
||||
#ifndef GL_ES |
||||
= 0u |
||||
#endif |
||||
; |
||||
#else |
||||
#define drawOffset 0u |
||||
#endif |
||||
|
||||
layout(std140 |
||||
#ifdef EXPLICIT_BINDING |
||||
, binding = 1 |
||||
#endif |
||||
) uniform TransformationProjection { |
||||
highp |
||||
#ifdef TWO_DIMENSIONS |
||||
/* Can't be a mat3 because of ANGLE, see DrawUniform in Phong.vert for |
||||
details */ |
||||
mat3x4 |
||||
#elif defined(THREE_DIMENSIONS) |
||||
mat4 |
||||
#else |
||||
#error |
||||
#endif |
||||
transformationProjectionMatrices[DRAW_COUNT]; |
||||
}; |
||||
#endif |
||||
|
||||
/* Inputs */ |
||||
|
||||
#ifdef EXPLICIT_ATTRIB_LOCATION |
||||
layout(location = POSITION_ATTRIBUTE_LOCATION) |
||||
#endif |
||||
#ifdef TWO_DIMENSIONS |
||||
in highp vec2 position; |
||||
#elif defined(THREE_DIMENSIONS) |
||||
in highp vec4 position; |
||||
#else |
||||
#error |
||||
#endif |
||||
|
||||
#ifdef EXPLICIT_ATTRIB_LOCATION |
||||
layout(location = LINE_DIRECTION_ATTRIBUTE_LOCATION) |
||||
#endif |
||||
#ifdef TWO_DIMENSIONS |
||||
in highp vec2 direction_; |
||||
#elif defined(THREE_DIMENSIONS) |
||||
in highp vec3 direction_; |
||||
#else |
||||
#error |
||||
#endif |
||||
|
||||
#ifdef EXPLICIT_ATTRIB_LOCATION |
||||
layout(location = LINE_NEIGHBOR_DIRECTION_ATTRIBUTE_LOCATION) |
||||
#endif |
||||
#ifdef TWO_DIMENSIONS |
||||
in highp vec2 neighborDirection_; |
||||
#elif defined(THREE_DIMENSIONS) |
||||
in highp vec3 neighborDirection_; |
||||
#else |
||||
#error |
||||
#endif |
||||
|
||||
#ifdef VERTEX_COLOR |
||||
#ifdef EXPLICIT_ATTRIB_LOCATION |
||||
layout(location = COLOR_ATTRIBUTE_LOCATION) |
||||
#endif |
||||
in lowp vec4 vertexColor; |
||||
#endif |
||||
|
||||
#ifdef INSTANCED_OBJECT_ID |
||||
#ifdef EXPLICIT_ATTRIB_LOCATION |
||||
layout(location = OBJECT_ID_ATTRIBUTE_LOCATION) |
||||
#endif |
||||
in highp uint instanceObjectId; |
||||
#endif |
||||
|
||||
#ifdef INSTANCED_TRANSFORMATION |
||||
#ifdef EXPLICIT_ATTRIB_LOCATION |
||||
layout(location = TRANSFORMATION_MATRIX_ATTRIBUTE_LOCATION) |
||||
#endif |
||||
#ifdef TWO_DIMENSIONS |
||||
in highp mat3 instancedTransformationMatrix; |
||||
#elif defined(THREE_DIMENSIONS) |
||||
in highp mat4 instancedTransformationMatrix; |
||||
#else |
||||
#error |
||||
#endif |
||||
#endif |
||||
|
||||
/* Outputs */ |
||||
|
||||
out highp vec2 centerDistanceSigned; |
||||
out highp float halfSegmentLength; |
||||
|
||||
#ifdef VERTEX_COLOR |
||||
out lowp vec4 interpolatedVertexColor; |
||||
#endif |
||||
|
||||
#ifdef INSTANCED_OBJECT_ID |
||||
flat out highp uint interpolatedInstanceObjectId; |
||||
#endif |
||||
|
||||
#ifdef MULTI_DRAW |
||||
flat out highp uint drawId; |
||||
#endif |
||||
|
||||
/* Same as Math::Vector2::perpendicular() */ |
||||
vec2 perpendicular(vec2 a) { |
||||
return vec2(-a.y, a.x); |
||||
} |
||||
|
||||
void main() { |
||||
#ifdef UNIFORM_BUFFERS |
||||
#ifdef MULTI_DRAW |
||||
drawId = drawOffset + uint( |
||||
#ifndef GL_ES |
||||
gl_DrawIDARB /* Using GL_ARB_shader_draw_parameters, not GLSL 4.6 */ |
||||
#else |
||||
gl_DrawID |
||||
#endif |
||||
); |
||||
#else |
||||
#define drawId drawOffset |
||||
#endif |
||||
|
||||
#ifdef TWO_DIMENSIONS |
||||
highp const mat3 transformationProjectionMatrix = mat3(transformationProjectionMatrices[drawId]); |
||||
#elif defined(THREE_DIMENSIONS) |
||||
highp const mat4 transformationProjectionMatrix = transformationProjectionMatrices[drawId]; |
||||
#else |
||||
#error |
||||
#endif |
||||
#endif |
||||
|
||||
#ifdef TWO_DIMENSIONS |
||||
const vec2 lineCenterPosition = (transformationProjectionMatrix* |
||||
#ifdef INSTANCED_TRANSFORMATION |
||||
instancedTransformationMatrix* |
||||
#endif |
||||
vec3(position, 1.0)).xy; |
||||
|
||||
// TODO take prev/next positions, this makes no sense |
||||
const vec2 direction = (transformationProjectionMatrix* |
||||
#ifdef INSTANCED_TRANSFORMATION |
||||
instancedTransformationMatrix* |
||||
#endif |
||||
vec3(position + direction_, 1.0)).xy - lineCenterPosition; |
||||
|
||||
const vec2 neighborDirection = (transformationProjectionMatrix* |
||||
#ifdef INSTANCED_TRANSFORMATION |
||||
instancedTransformationMatrix* |
||||
#endif |
||||
vec3(position + neighborDirection_, 1.0)).xy - lineCenterPosition; |
||||
|
||||
const float directionLength = length(direction); |
||||
// TODO since this is used just for AA, set to a special value in case of |
||||
// a line joint that shouldn't be AAd? |
||||
halfSegmentLength = length(direction*0.5*viewportSize/2.0); |
||||
// TODO zero-sized lines better? |
||||
const vec2 directionNormalized = directionLength == 0.0 ? vec2(1.0, 0.0) : direction/directionLength; |
||||
|
||||
/* Line width includes also twice the smoothness radius, some extra padding |
||||
on top, and is rounded to whole pixels. So for the edge distance we need |
||||
half of it. */ |
||||
// TODO ref the paper here; actually just drop all that, smoothstep FTW |
||||
const float edgeDistance = ceil(width + 2.0*smoothness)*0.5; |
||||
|
||||
/* Copied from MeshTools::generateLines() internals for completenes. The |
||||
position is always either `A` or `B` for all four quad corners, the `d` |
||||
comes in the direction attribute, `pd`/`nd` in neighborDirection and |
||||
the vertex order, which is (4n +) 0/1/2/3, in gl_VertexID. |
||||
|
||||
0-d->-------2-d-> |
||||
| / \ |
||||
A---------B nd |
||||
| / \ v |
||||
1-d->---3-d-> \ |
||||
\ \ . |
||||
nd . . |
||||
v C . */ |
||||
// TODO redo all this here |
||||
/* The perpendicular direction is rotating 90° counterclockwise. Which |
||||
means for points 1 and 3 (i.e., gl_VertexID not divisible by 2) we need |
||||
to negate it to point the other way. */ |
||||
// TODO zero-sized lines do what? |
||||
const float edgeSign = (gl_VertexID & 1) == 0 ? 1.0 : -1.0; |
||||
const float capSign = (gl_VertexID & 2) == 0 ? -1.0 : 1.0; |
||||
const float edgeDistanceSigned = edgeDistance*edgeSign; |
||||
// vec2 edgeDirection = perpendicular(directionNormalized)*edgeDistanceSigned*2.0/viewportSize; |
||||
|
||||
// float centerDirection |
||||
vec2 edgeDirection; |
||||
|
||||
/* Distance to center, passed to the fragment shader. It's chosen in a way |
||||
that interpolates to a zero vector in the quad center, and the area |
||||
where `abs(centerDirection) <= [d+w,w]` is inside the line. Inside the |
||||
line strip (where there's no line caps, shown on the left) the X value |
||||
is always 0, resulting in no antialiasing done on the beginning/end edge |
||||
in order to join tightly with the neigboring segments. |
||||
|
||||
0------------------2 0-----------------------------2 |
||||
[0,+w]-------------[0,+w] [-d-w,+w]------------------[+d+w,+w] |
||||
| | | | | | |
||||
[0,0] [0,0] [0,0] [-d-w,0] [0,0] [+d+w,0] |
||||
| | | | | | |
||||
[0,-w]-------------[0,-w] [-d-w,-w]------------------[+d+w,-w] |
||||
1------------------3 1-----------------------------3 */ |
||||
// TODO handle caps |
||||
centerDistanceSigned.y = edgeDistanceSigned; |
||||
|
||||
/* If the neighbor direction is a NaN, it means we're at the line cap -- |
||||
the quad gets extended beyond A or B in the direction of the segment, |
||||
as shown with the points 0 and 1: |
||||
|
||||
0--+--- |
||||
| | |
||||
| A--d->-- |
||||
| | |
||||
1--+--- |
||||
|
||||
For points 0 and 1 it'll be in the negative direction `d`, for points 2 |
||||
and 3 in positive `d`. */ |
||||
if(all(isnan(neighborDirection))) { |
||||
edgeDirection = |
||||
(directionNormalized*capSign + |
||||
perpendicular(directionNormalized)*edgeSign)*edgeDistance*2.0/viewportSize |
||||
; |
||||
centerDistanceSigned.x = (edgeDistance + halfSegmentLength)*capSign; |
||||
|
||||
/* Otherwise we need to create a tight joint with the neighboring line |
||||
segment, as shown with the points 2 and 3. Given normalized direction |
||||
`d` and neighbor direction `nd`, `normalized(d + nd)` is the "average" |
||||
direction of the two and `perpendicular(normalized(d + nd))` gives us |
||||
the direction from B to 2: |
||||
|
||||
--------+----2 |
||||
| / alpha/2 |
||||
w | / j |
||||
|/ |
||||
--d->-B |
||||
alpha/2 / \ |
||||
/ nd |
||||
/ v |
||||
----3 |
||||
|
||||
With `alpha` being the angle between `d` and `nd`, `alpha/2` appears in |
||||
two right triangles and the following holds, `w` being the edge distance |
||||
from above, and `j` being the length that's needed to scale `perpendicular(normalized(d + nd))` to get point 2: |
||||
|
||||
|d + nd| w 2 w |
||||
sin(alpha/2) = -------- = --- --> j = -------- |
||||
2 |d| j |d + nd| |
||||
|
||||
Point 3 is then just in the opposite direction; for the other side it's |
||||
done equivalently. */ |
||||
} else { |
||||
// edgeDirection = perpendicular(directionNormalized)*edgeSign*edgeDistance*2.0/viewportSize; |
||||
|
||||
const vec2 averageDirection = capSign*directionNormalized + normalize(neighborDirection); |
||||
const float averageDirectionLength = length(averageDirection); |
||||
edgeDirection = perpendicular(averageDirection)*(capSign*edgeSign*edgeDistance*4.0/averageDirectionLength)/viewportSize; |
||||
|
||||
// const float ex = sqrt((4.0*edgeDistance*edgeDistance/(averageDirectionLength*averageDirectionLength)) - edgeDistance*edgeDistance); |
||||
const float ex = sqrt(dot(edgeDirection, edgeDirection) - edgeDistance*edgeDistance); |
||||
|
||||
// edgeDirection = -perpendicular(averageDirection)*(1.0*edgeDistance*edgeSign*capSign/averageDirectionLength) |
||||
// *2.0/viewportSize; |
||||
|
||||
// TODO it can't be 0!! it also has to include the skew in here but |
||||
// then somehow be marked to not smooth |
||||
centerDistanceSigned.x = halfSegmentLength*capSign;// + ex*sign(dot(direction*capSign, edgeDirection)); |
||||
} |
||||
|
||||
// TODO cap ends / joints, depending on neighborDirection size |
||||
|
||||
gl_Position.xyzw = vec4(lineCenterPosition + edgeDirection, 0.0, 1.0); |
||||
#elif defined(THREE_DIMENSIONS) |
||||
// TODO 3D, how to handle perspective? multiply edgeDistance with w? |
||||
gl_Position = transformationProjectionMatrix* |
||||
#ifdef INSTANCED_TRANSFORMATION |
||||
instancedTransformationMatrix* |
||||
#endif |
||||
position; |
||||
#else |
||||
#error |
||||
#endif |
||||
|
||||
#ifdef VERTEX_COLOR |
||||
/* Vertex colors, if enabled */ |
||||
interpolatedVertexColor = vertexColor; |
||||
#endif |
||||
|
||||
#ifdef INSTANCED_OBJECT_ID |
||||
/* Instanced object ID, if enabled */ |
||||
interpolatedInstanceObjectId = instanceObjectId; |
||||
#endif |
||||
} |
||||
@ -0,0 +1,417 @@
|
||||
/*
|
||||
This file is part of Magnum. |
||||
|
||||
Copyright © 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019, |
||||
2020, 2021, 2022 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. |
||||
*/ |
||||
|
||||
#include "LineGL.h" |
||||
|
||||
#include <Corrade/Containers/EnumSet.hpp> |
||||
#include <Corrade/Utility/Resource.h> |
||||
|
||||
#include "Magnum/GL/Context.h" |
||||
#include "Magnum/GL/Extensions.h" |
||||
#include "Magnum/GL/Shader.h" |
||||
#include "Magnum/Math/Color.h" |
||||
#include "Magnum/Math/Matrix3.h" |
||||
#include "Magnum/Math/Matrix4.h" |
||||
#include "Magnum/Shaders/Implementation/CreateCompatibilityShader.h" |
||||
|
||||
#ifndef MAGNUM_TARGET_GLES2 |
||||
#include <Corrade/Utility/FormatStl.h> |
||||
|
||||
#include "Magnum/GL/Buffer.h" |
||||
#endif |
||||
|
||||
namespace Magnum { namespace Shaders { |
||||
|
||||
namespace { |
||||
enum: Int { |
||||
/* 0/1/2/3 taken by Phong (A/D/S/N), 4 by MeshVisualizer colormap, 5 by
|
||||
object ID textures, 6 by Vector */ |
||||
TextureUnit = 7 |
||||
}; |
||||
|
||||
#ifndef MAGNUM_TARGET_GLES2 |
||||
enum: Int { |
||||
/* Not using the zero binding to avoid conflicts with
|
||||
ProjectionBufferBinding from other shaders which can likely stay |
||||
bound to the same buffer for the whole time */ |
||||
TransformationProjectionBufferBinding = 1, |
||||
DrawBufferBinding = 2, |
||||
MaterialBufferBinding = 3 |
||||
}; |
||||
#endif |
||||
} |
||||
|
||||
template<UnsignedInt dimensions> typename LineGL<dimensions>::CompileState LineGL<dimensions>::compile(const Configuration& configuration) { |
||||
#ifndef MAGNUM_TARGET_GLES2 |
||||
CORRADE_ASSERT(!(configuration.flags() >= Flag::UniformBuffers) || configuration.materialCount(), |
||||
"Shaders::LineGL: material count can't be zero", CompileState{NoCreate}); |
||||
CORRADE_ASSERT(!(configuration.flags() >= Flag::UniformBuffers) || configuration.drawCount(), |
||||
"Shaders::LineGL: draw count can't be zero", CompileState{NoCreate}); |
||||
#endif |
||||
|
||||
#ifndef MAGNUM_TARGET_GLES |
||||
if(configuration.flags() >= Flag::UniformBuffers) |
||||
MAGNUM_ASSERT_GL_EXTENSION_SUPPORTED(GL::Extensions::ARB::uniform_buffer_object); |
||||
#endif |
||||
#ifndef MAGNUM_TARGET_GLES2 |
||||
if(configuration.flags() >= Flag::MultiDraw) { |
||||
#ifndef MAGNUM_TARGET_GLES |
||||
MAGNUM_ASSERT_GL_EXTENSION_SUPPORTED(GL::Extensions::ARB::shader_draw_parameters); |
||||
#elif !defined(MAGNUM_TARGET_WEBGL) |
||||
MAGNUM_ASSERT_GL_EXTENSION_SUPPORTED(GL::Extensions::ANGLE::multi_draw); |
||||
#else |
||||
MAGNUM_ASSERT_GL_EXTENSION_SUPPORTED(GL::Extensions::WEBGL::multi_draw); |
||||
#endif |
||||
} |
||||
#endif |
||||
|
||||
#ifdef MAGNUM_BUILD_STATIC |
||||
/* Import resources on static build, if not already */ |
||||
if(!Utility::Resource::hasGroup("MagnumShadersGL")) |
||||
importShaderResources(); |
||||
#endif |
||||
Utility::Resource rs("MagnumShadersGL"); |
||||
|
||||
const GL::Context& context = GL::Context::current(); |
||||
|
||||
const GL::Version version = context.supportedVersion({ |
||||
#ifndef MAGNUM_TARGET_GLES |
||||
GL::Version::GL320, GL::Version::GL310, GL::Version::GL300, GL::Version::GL210 |
||||
#else |
||||
GL::Version::GLES300, GL::Version::GLES200 |
||||
#endif |
||||
}); |
||||
|
||||
GL::Shader vert = Implementation::createCompatibilityShader(rs, version, GL::Shader::Type::Vertex); |
||||
GL::Shader frag = Implementation::createCompatibilityShader(rs, version, GL::Shader::Type::Fragment); |
||||
|
||||
vert.addSource(configuration.flags() & Flag::VertexColor ? "#define VERTEX_COLOR\n" : "") |
||||
.addSource(dimensions == 2 ? "#define TWO_DIMENSIONS\n" : "#define THREE_DIMENSIONS\n") |
||||
#ifndef MAGNUM_TARGET_GLES2 |
||||
.addSource(configuration.flags() >= Flag::InstancedObjectId ? "#define INSTANCED_OBJECT_ID\n" : "") |
||||
#endif |
||||
.addSource(configuration.flags() & Flag::InstancedTransformation ? "#define INSTANCED_TRANSFORMATION\n" : ""); |
||||
#ifndef MAGNUM_TARGET_GLES2 |
||||
if(configuration.flags() >= Flag::UniformBuffers) { |
||||
vert.addSource(Utility::formatString( |
||||
"#define UNIFORM_BUFFERS\n" |
||||
"#define DRAW_COUNT {}\n", |
||||
configuration.drawCount())); |
||||
vert.addSource(configuration.flags() >= Flag::MultiDraw ? "#define MULTI_DRAW\n" : ""); |
||||
} |
||||
#endif |
||||
vert.addSource(rs.getString("generic.glsl")) |
||||
.addSource(rs.getString("Line.vert")); |
||||
frag.addSource(configuration.flags() & Flag::VertexColor ? "#define VERTEX_COLOR\n" : "") |
||||
#ifndef MAGNUM_TARGET_GLES2 |
||||
.addSource(configuration.flags() & Flag::ObjectId ? "#define OBJECT_ID\n" : "") |
||||
.addSource(configuration.flags() >= Flag::InstancedObjectId ? "#define INSTANCED_OBJECT_ID\n" : "") |
||||
#endif |
||||
; |
||||
#ifndef MAGNUM_TARGET_GLES2 |
||||
if(configuration.flags() >= Flag::UniformBuffers) { |
||||
frag.addSource(Utility::formatString( |
||||
"#define UNIFORM_BUFFERS\n" |
||||
"#define DRAW_COUNT {}\n" |
||||
"#define MATERIAL_COUNT {}\n", |
||||
configuration.drawCount(), |
||||
configuration.materialCount())); |
||||
frag.addSource(configuration.flags() >= Flag::MultiDraw ? "#define MULTI_DRAW\n" : ""); |
||||
} |
||||
#endif |
||||
frag.addSource(rs.getString("generic.glsl")) |
||||
.addSource(rs.getString("Line.frag")); |
||||
|
||||
vert.submitCompile(); |
||||
frag.submitCompile(); |
||||
|
||||
LineGL<dimensions> out{NoInit}; |
||||
out._flags = configuration.flags(); |
||||
#ifndef MAGNUM_TARGET_GLES2 |
||||
out._materialCount = configuration.materialCount(); |
||||
out._drawCount = configuration.drawCount(); |
||||
#endif |
||||
|
||||
out.attachShaders({vert, frag}); |
||||
|
||||
/* ES3 has this done in the shader directly and doesn't even provide
|
||||
bindFragmentDataLocation() */ |
||||
#if !defined(MAGNUM_TARGET_GLES) || defined(MAGNUM_TARGET_GLES2) |
||||
#ifndef MAGNUM_TARGET_GLES |
||||
if(!context.isExtensionSupported<GL::Extensions::ARB::explicit_attrib_location>(version)) |
||||
#endif |
||||
{ |
||||
out.bindAttributeLocation(Position::Location, "position"); |
||||
out.bindAttributeLocation(LineDirection::Location, "direction"); |
||||
out.bindAttributeLocation(LineNeighborDirection::Location, "neighborDirection"); |
||||
if(configuration.flags() & Flag::VertexColor) |
||||
out.bindAttributeLocation(Color3::Location, "vertexColor"); /* Color4 is the same */ |
||||
#ifndef MAGNUM_TARGET_GLES2 |
||||
if(configuration.flags() & Flag::ObjectId) { |
||||
out.bindFragmentDataLocation(ColorOutput, "color"); |
||||
out.bindFragmentDataLocation(ObjectIdOutput, "objectId"); |
||||
} |
||||
if(configuration.flags() >= Flag::InstancedObjectId) |
||||
out.bindAttributeLocation(ObjectId::Location, "instanceObjectId"); |
||||
#endif |
||||
if(configuration.flags() & Flag::InstancedTransformation) |
||||
out.bindAttributeLocation(TransformationMatrix::Location, "instancedTransformationMatrix"); |
||||
} |
||||
#endif |
||||
|
||||
out.submitLink(); |
||||
|
||||
return CompileState{std::move(out), std::move(vert), std::move(frag), version}; |
||||
} |
||||
|
||||
template<UnsignedInt dimensions> LineGL<dimensions>::LineGL(CompileState&& state): LineGL{static_cast<LineGL&&>(std::move(state))} { |
||||
#ifdef CORRADE_GRACEFUL_ASSERT |
||||
/* When graceful assertions fire from within compile(), we get a NoCreate'd
|
||||
CompileState. Exiting makes it possible to test the assert. */ |
||||
if(!id()) return; |
||||
#endif |
||||
|
||||
CORRADE_INTERNAL_ASSERT_OUTPUT(checkLink({GL::Shader(state._vert), GL::Shader(state._frag)})); |
||||
|
||||
const GL::Context& context = GL::Context::current(); |
||||
const GL::Version version = state._version; |
||||
|
||||
#ifndef MAGNUM_TARGET_GLES |
||||
if(!context.isExtensionSupported<GL::Extensions::ARB::explicit_uniform_location>(version)) |
||||
#endif |
||||
{ |
||||
_viewportSizeUniform = uniformLocation("viewportSize"); |
||||
#ifndef MAGNUM_TARGET_GLES2 |
||||
if(_flags >= Flag::UniformBuffers) { |
||||
if(_drawCount > 1) _drawOffsetUniform = uniformLocation("drawOffset"); |
||||
} else |
||||
#endif |
||||
{ |
||||
_transformationProjectionMatrixUniform = uniformLocation("transformationProjectionMatrix"); |
||||
_widthUniform = uniformLocation("width"); |
||||
_smoothnessUniform = uniformLocation("smoothness"); |
||||
_backgroundColorUniform = uniformLocation("backgroundColor"); |
||||
_colorUniform = uniformLocation("color"); |
||||
#ifndef MAGNUM_TARGET_GLES2 |
||||
if(_flags & Flag::ObjectId) _objectIdUniform = uniformLocation("objectId"); |
||||
#endif |
||||
} |
||||
} |
||||
|
||||
#ifndef MAGNUM_TARGET_GLES |
||||
if(!context.isExtensionSupported<GL::Extensions::ARB::shading_language_420pack>(version)) |
||||
#endif |
||||
{ |
||||
#ifndef MAGNUM_TARGET_GLES2 |
||||
if(_flags >= Flag::UniformBuffers) { |
||||
setUniformBlockBinding(uniformBlockIndex("TransformationProjection"), TransformationProjectionBufferBinding); |
||||
setUniformBlockBinding(uniformBlockIndex("Draw"), DrawBufferBinding); |
||||
setUniformBlockBinding(uniformBlockIndex("Material"), MaterialBufferBinding); |
||||
} |
||||
#endif |
||||
} |
||||
|
||||
/* Set defaults in OpenGL ES (for desktop they are set in shader code itself) */ |
||||
#ifdef MAGNUM_TARGET_GLES |
||||
#ifndef MAGNUM_TARGET_GLES2 |
||||
if(_flags >= Flag::UniformBuffers) { |
||||
/* Draw offset is zero by default */ |
||||
} else |
||||
#endif |
||||
{ |
||||
setTransformationProjectionMatrix(MatrixTypeFor<dimensions, Float>{Math::IdentityInit}); |
||||
setColor(Magnum::Color4{1.0f}); |
||||
/* Object ID is zero by default */ |
||||
} |
||||
#endif |
||||
|
||||
static_cast<void>(version); |
||||
static_cast<void>(context); |
||||
} |
||||
|
||||
template<UnsignedInt dimensions> LineGL<dimensions>::LineGL(const Configuration& configuration): LineGL{compile(configuration)} {} |
||||
|
||||
template<UnsignedInt dimensions> LineGL<dimensions>::LineGL(NoInitT) {} |
||||
|
||||
template<UnsignedInt dimensions> LineGL<dimensions>& LineGL<dimensions>::setTransformationProjectionMatrix(const MatrixTypeFor<dimensions, Float>& matrix) { |
||||
#ifndef MAGNUM_TARGET_GLES2 |
||||
CORRADE_ASSERT(!(_flags >= Flag::UniformBuffers), |
||||
"Shaders::LineGL::setTransformationProjectionMatrix(): the shader was created with uniform buffers enabled", *this); |
||||
#endif |
||||
setUniform(_transformationProjectionMatrixUniform, matrix); |
||||
return *this; |
||||
} |
||||
|
||||
template<UnsignedInt dimensions> LineGL<dimensions>& LineGL<dimensions>::setViewportSize(const Vector2& size) { |
||||
setUniform(_viewportSizeUniform, size); |
||||
return *this; |
||||
} |
||||
|
||||
template<UnsignedInt dimensions> LineGL<dimensions>& LineGL<dimensions>::setWidth(const Float width) { |
||||
#ifndef MAGNUM_TARGET_GLES2 |
||||
CORRADE_ASSERT(!(_flags >= Flag::UniformBuffers), |
||||
"Shaders::LineGL::setColor(): the shader was created with uniform buffers enabled", *this); |
||||
#endif |
||||
setUniform(_widthUniform, width); |
||||
return *this; |
||||
} |
||||
|
||||
template<UnsignedInt dimensions> LineGL<dimensions>& LineGL<dimensions>::setSmoothness(const Float smoothness) { |
||||
#ifndef MAGNUM_TARGET_GLES2 |
||||
CORRADE_ASSERT(!(_flags >= Flag::UniformBuffers), |
||||
"Shaders::LineGL::setColor(): the shader was created with uniform buffers enabled", *this); |
||||
#endif |
||||
setUniform(_smoothnessUniform, smoothness); |
||||
return *this; |
||||
} |
||||
|
||||
template<UnsignedInt dimensions> LineGL<dimensions>& LineGL<dimensions>::setBackgroundColor(const Magnum::Color4& color) { |
||||
#ifndef MAGNUM_TARGET_GLES2 |
||||
CORRADE_ASSERT(!(_flags >= Flag::UniformBuffers), |
||||
"Shaders::LineGL::setColor(): the shader was created with uniform buffers enabled", *this); |
||||
#endif |
||||
setUniform(_backgroundColorUniform, color); |
||||
return *this; |
||||
} |
||||
|
||||
template<UnsignedInt dimensions> LineGL<dimensions>& LineGL<dimensions>::setColor(const Magnum::Color4& color) { |
||||
#ifndef MAGNUM_TARGET_GLES2 |
||||
CORRADE_ASSERT(!(_flags >= Flag::UniformBuffers), |
||||
"Shaders::LineGL::setColor(): the shader was created with uniform buffers enabled", *this); |
||||
#endif |
||||
setUniform(_colorUniform, color); |
||||
return *this; |
||||
} |
||||
|
||||
#ifndef MAGNUM_TARGET_GLES2 |
||||
template<UnsignedInt dimensions> LineGL<dimensions>& LineGL<dimensions>::setObjectId(UnsignedInt id) { |
||||
CORRADE_ASSERT(!(_flags >= Flag::UniformBuffers), |
||||
"Shaders::LineGL::setObjectId(): the shader was created with uniform buffers enabled", *this); |
||||
CORRADE_ASSERT(_flags & Flag::ObjectId, |
||||
"Shaders::LineGL::setObjectId(): the shader was not created with object ID enabled", *this); |
||||
setUniform(_objectIdUniform, id); |
||||
return *this; |
||||
} |
||||
#endif |
||||
|
||||
#ifndef MAGNUM_TARGET_GLES2 |
||||
template<UnsignedInt dimensions> LineGL<dimensions>& LineGL<dimensions>::setDrawOffset(const UnsignedInt offset) { |
||||
CORRADE_ASSERT(_flags >= Flag::UniformBuffers, |
||||
"Shaders::LineGL::setDrawOffset(): the shader was not created with uniform buffers enabled", *this); |
||||
CORRADE_ASSERT(offset < _drawCount, |
||||
"Shaders::LineGL::setDrawOffset(): draw offset" << offset << "is out of bounds for" << _drawCount << "draws", *this); |
||||
if(_drawCount > 1) setUniform(_drawOffsetUniform, offset); |
||||
return *this; |
||||
} |
||||
|
||||
template<UnsignedInt dimensions> LineGL<dimensions>& LineGL<dimensions>::bindTransformationProjectionBuffer(GL::Buffer& buffer) { |
||||
CORRADE_ASSERT(_flags >= Flag::UniformBuffers, |
||||
"Shaders::LineGL::bindTransformationProjectionBuffer(): the shader was not created with uniform buffers enabled", *this); |
||||
buffer.bind(GL::Buffer::Target::Uniform, TransformationProjectionBufferBinding); |
||||
return *this; |
||||
} |
||||
|
||||
template<UnsignedInt dimensions> LineGL<dimensions>& LineGL<dimensions>::bindTransformationProjectionBuffer(GL::Buffer& buffer, const GLintptr offset, const GLsizeiptr size) { |
||||
CORRADE_ASSERT(_flags >= Flag::UniformBuffers, |
||||
"Shaders::LineGL::bindTransformationProjectionBuffer(): the shader was not created with uniform buffers enabled", *this); |
||||
buffer.bind(GL::Buffer::Target::Uniform, TransformationProjectionBufferBinding, offset, size); |
||||
return *this; |
||||
} |
||||
|
||||
template<UnsignedInt dimensions> LineGL<dimensions>& LineGL<dimensions>::bindDrawBuffer(GL::Buffer& buffer) { |
||||
CORRADE_ASSERT(_flags >= Flag::UniformBuffers, |
||||
"Shaders::LineGL::bindDrawBuffer(): the shader was not created with uniform buffers enabled", *this); |
||||
buffer.bind(GL::Buffer::Target::Uniform, DrawBufferBinding); |
||||
return *this; |
||||
} |
||||
|
||||
template<UnsignedInt dimensions> LineGL<dimensions>& LineGL<dimensions>::bindDrawBuffer(GL::Buffer& buffer, const GLintptr offset, const GLsizeiptr size) { |
||||
CORRADE_ASSERT(_flags >= Flag::UniformBuffers, |
||||
"Shaders::LineGL::bindDrawBuffer(): the shader was not created with uniform buffers enabled", *this); |
||||
buffer.bind(GL::Buffer::Target::Uniform, DrawBufferBinding, offset, size); |
||||
return *this; |
||||
} |
||||
|
||||
template<UnsignedInt dimensions> LineGL<dimensions>& LineGL<dimensions>::bindMaterialBuffer(GL::Buffer& buffer) { |
||||
CORRADE_ASSERT(_flags >= Flag::UniformBuffers, |
||||
"Shaders::LineGL::bindMaterialBuffer(): the shader was not created with uniform buffers enabled", *this); |
||||
buffer.bind(GL::Buffer::Target::Uniform, MaterialBufferBinding); |
||||
return *this; |
||||
} |
||||
|
||||
template<UnsignedInt dimensions> LineGL<dimensions>& LineGL<dimensions>::bindMaterialBuffer(GL::Buffer& buffer, const GLintptr offset, const GLsizeiptr size) { |
||||
CORRADE_ASSERT(_flags >= Flag::UniformBuffers, |
||||
"Shaders::LineGL::bindMaterialBuffer(): the shader was not created with uniform buffers enabled", *this); |
||||
buffer.bind(GL::Buffer::Target::Uniform, MaterialBufferBinding, offset, size); |
||||
return *this; |
||||
} |
||||
#endif |
||||
|
||||
template class MAGNUM_SHADERS_EXPORT LineGL<2>; |
||||
template class MAGNUM_SHADERS_EXPORT LineGL<3>; |
||||
|
||||
namespace Implementation { |
||||
|
||||
Debug& operator<<(Debug& debug, const LineGLFlag value) { |
||||
debug << "Shaders::LineGL::Flag" << Debug::nospace; |
||||
|
||||
switch(value) { |
||||
/* LCOV_EXCL_START */ |
||||
#define _c(v) case LineGLFlag::v: return debug << "::" #v; |
||||
_c(VertexColor) |
||||
#ifndef MAGNUM_TARGET_GLES2 |
||||
_c(ObjectId) |
||||
_c(InstancedObjectId) |
||||
#endif |
||||
_c(InstancedTransformation) |
||||
#ifndef MAGNUM_TARGET_GLES2 |
||||
_c(UniformBuffers) |
||||
_c(MultiDraw) |
||||
#endif |
||||
#undef _c |
||||
/* LCOV_EXCL_STOP */ |
||||
} |
||||
|
||||
return debug << "(" << Debug::nospace << reinterpret_cast<void*>(UnsignedShort(value)) << Debug::nospace << ")"; |
||||
} |
||||
|
||||
Debug& operator<<(Debug& debug, const LineGLFlags value) { |
||||
return Containers::enumSetDebugOutput(debug, value, "Shaders::LineGL::Flags{}", { |
||||
LineGLFlag::VertexColor, |
||||
#ifndef MAGNUM_TARGET_GLES2 |
||||
LineGLFlag::InstancedObjectId, /* Superset of ObjectId */ |
||||
LineGLFlag::ObjectId, |
||||
#endif |
||||
LineGLFlag::InstancedTransformation, |
||||
#ifndef MAGNUM_TARGET_GLES2 |
||||
LineGLFlag::MultiDraw, /* Superset of UniformBuffers */ |
||||
LineGLFlag::UniformBuffers |
||||
#endif |
||||
}); |
||||
} |
||||
|
||||
} |
||||
|
||||
}} |
||||
@ -0,0 +1,281 @@
|
||||
#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 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. |
||||
*/ |
||||
|
||||
#include "Magnum/DimensionTraits.h" |
||||
#include "Magnum/GL/AbstractShaderProgram.h" |
||||
#include "Magnum/Shaders/GenericGL.h" |
||||
#include "Magnum/Shaders/glShaderWrapper.h" |
||||
#include "Magnum/Shaders/visibility.h" |
||||
|
||||
namespace Magnum { namespace Shaders { |
||||
|
||||
namespace Implementation { |
||||
enum class LineGLFlag: UnsignedShort { |
||||
VertexColor = 1 << 0, |
||||
#ifndef MAGNUM_TARGET_GLES2 |
||||
ObjectId = 1 << 1, |
||||
InstancedObjectId = (1 << 2)|ObjectId, |
||||
#endif |
||||
InstancedTransformation = 1 << 3, |
||||
#ifndef MAGNUM_TARGET_GLES2 |
||||
UniformBuffers = 1 << 4, |
||||
MultiDraw = UniformBuffers|(1 << 5) |
||||
#endif |
||||
}; |
||||
typedef Containers::EnumSet<LineGLFlag> LineGLFlags; |
||||
} |
||||
|
||||
template<UnsignedInt dimensions> class MAGNUM_SHADERS_EXPORT LineGL: public GL::AbstractShaderProgram { |
||||
public: |
||||
class Configuration; |
||||
class CompileState; |
||||
|
||||
typedef typename GenericGL<dimensions>::Position Position; |
||||
|
||||
// TODO move to Generic
|
||||
typedef GL::Attribute<3, VectorTypeFor<dimensions, Float>> LineDirection; |
||||
typedef GL::Attribute<5, VectorTypeFor<dimensions, Float>> LineNeighborDirection; |
||||
|
||||
typedef typename GenericGL<dimensions>::Color3 Color3; |
||||
|
||||
typedef typename GenericGL<dimensions>::Color4 Color4; |
||||
|
||||
#ifndef MAGNUM_TARGET_GLES2 |
||||
typedef typename GenericGL<dimensions>::ObjectId ObjectId; |
||||
#endif |
||||
|
||||
typedef typename GenericGL<dimensions>::TransformationMatrix TransformationMatrix; |
||||
|
||||
enum: UnsignedInt { |
||||
ColorOutput = GenericGL<dimensions>::ColorOutput, |
||||
|
||||
#ifndef MAGNUM_TARGET_GLES2 |
||||
ObjectIdOutput = GenericGL<dimensions>::ObjectIdOutput |
||||
#endif |
||||
}; |
||||
|
||||
#ifdef DOXYGEN_GENERATING_OUTPUT |
||||
/**
|
||||
* @brief Flag |
||||
* |
||||
* @see @ref Flags, @ref flags() |
||||
*/ |
||||
enum class Flag: UnsignedShort { |
||||
VertexColor = 1 << 0, |
||||
#ifndef MAGNUM_TARGET_GLES2 |
||||
ObjectId = 1 << 1, |
||||
InstancedObjectId = (1 << 2)|ObjectId, |
||||
#endif |
||||
InstancedTransformation = 1 << 3, |
||||
#ifndef MAGNUM_TARGET_GLES2 |
||||
UniformBuffers = 1 << 4, |
||||
MultiDraw = UniformBuffers|(1 << 5) |
||||
#endif |
||||
}; |
||||
|
||||
/**
|
||||
* @brief Flags |
||||
* |
||||
* @see @ref flags() |
||||
*/ |
||||
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 |
||||
|
||||
static CompileState compile(const Configuration& configuration = Configuration{}); |
||||
|
||||
explicit LineGL(const Configuration& configuration = Configuration{}); |
||||
|
||||
explicit LineGL(CompileState&& state); |
||||
|
||||
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 */ |
||||
Flags flags() const { return _flags; } |
||||
|
||||
#ifndef MAGNUM_TARGET_GLES2 |
||||
UnsignedInt materialCount() const { return _materialCount; } |
||||
|
||||
UnsignedInt drawCount() const { return _drawCount; } |
||||
#endif |
||||
|
||||
// TODO split projection for 3D?
|
||||
LineGL<dimensions>& setTransformationProjectionMatrix(const MatrixTypeFor<dimensions, Float>& matrix); |
||||
|
||||
LineGL<dimensions>& setViewportSize(const Vector2& size); |
||||
|
||||
LineGL<dimensions>& setWidth(Float width); |
||||
|
||||
LineGL<dimensions>& setSmoothness(Float smoothness); |
||||
|
||||
LineGL<dimensions>& setBackgroundColor(const Magnum::Color4& color); |
||||
|
||||
LineGL<dimensions>& setColor(const Magnum::Color4& color); |
||||
|
||||
#ifndef MAGNUM_TARGET_GLES2 |
||||
LineGL<dimensions>& setObjectId(UnsignedInt id); |
||||
#endif |
||||
|
||||
#ifndef MAGNUM_TARGET_GLES2 |
||||
LineGL<dimensions>& setDrawOffset(UnsignedInt offset); |
||||
|
||||
LineGL<dimensions>& bindTransformationProjectionBuffer(GL::Buffer& buffer); |
||||
LineGL<dimensions>& bindTransformationProjectionBuffer(GL::Buffer& buffer, GLintptr offset, GLsizeiptr size); |
||||
|
||||
LineGL<dimensions>& bindDrawBuffer(GL::Buffer& buffer); |
||||
LineGL<dimensions>& bindDrawBuffer(GL::Buffer& buffer, GLintptr offset, GLsizeiptr size); |
||||
|
||||
LineGL<dimensions>& bindMaterialBuffer(GL::Buffer& buffer); |
||||
LineGL<dimensions>& bindMaterialBuffer(GL::Buffer& buffer, GLintptr offset, GLsizeiptr size); |
||||
#endif |
||||
|
||||
// TODO draw() overloads, as a macro in AbstractShaderProgram
|
||||
|
||||
private: |
||||
/* Creates the GL shader program object but does nothing else.
|
||||
Internal, used by compile(). */ |
||||
explicit LineGL(NoInitT); |
||||
|
||||
Flags _flags; |
||||
#ifndef MAGNUM_TARGET_GLES2 |
||||
UnsignedInt _materialCount{}, _drawCount{}; |
||||
#endif |
||||
Int _viewportSizeUniform{0}, |
||||
_transformationProjectionMatrixUniform{1}, |
||||
_widthUniform{2}, |
||||
_smoothnessUniform{3}, |
||||
_backgroundColorUniform{4}, |
||||
_colorUniform{5}; |
||||
#ifndef MAGNUM_TARGET_GLES2 |
||||
Int _objectIdUniform{6}; |
||||
/* Used instead of all other uniforms except viewportSize when
|
||||
Flag::UniformBuffers is set, so it can alias them */ |
||||
Int _drawOffsetUniform{1}; |
||||
#endif |
||||
}; |
||||
|
||||
/**
|
||||
@brief Configuration |
||||
|
||||
*/ |
||||
template<UnsignedInt dimensions> class LineGL<dimensions>::Configuration { |
||||
public: |
||||
explicit Configuration() = default; |
||||
|
||||
Configuration& setFlags(Flags flags) { |
||||
_flags = flags; |
||||
return *this; |
||||
} |
||||
|
||||
Flags flags() const { return _flags; } |
||||
|
||||
#ifndef MAGNUM_TARGET_GLES2 |
||||
Configuration& setMaterialCount(UnsignedInt count) { |
||||
_materialCount = count; |
||||
return *this; |
||||
} |
||||
|
||||
UnsignedInt materialCount() const { return _materialCount; } |
||||
|
||||
Configuration& setDrawCount(UnsignedInt count) { |
||||
_drawCount = count; |
||||
return *this; |
||||
} |
||||
|
||||
UnsignedInt drawCount() const { return _drawCount; } |
||||
#endif |
||||
|
||||
private: |
||||
Flags _flags; |
||||
#ifndef MAGNUM_TARGET_GLES2 |
||||
UnsignedInt _materialCount{1}; |
||||
UnsignedInt _drawCount{1}; |
||||
#endif |
||||
}; |
||||
|
||||
/**
|
||||
@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, GL::Version version): LineGL<dimensions>{std::move(shader)}, _vert{std::move(vert)}, _frag{std::move(frag)}, _version{version} {} |
||||
|
||||
Implementation::GLShaderWrapper _vert, _frag; |
||||
GL::Version _version; |
||||
}; |
||||
|
||||
/**
|
||||
@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} */ |
||||
template<UnsignedInt dimensions> Debug& operator<<(Debug& debug, LineGL<dimensions>::Flag value); |
||||
|
||||
/** @debugoperatorclassenum{LineGL,LineGL::Flags} */ |
||||
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); |
||||
CORRADE_ENUMSET_OPERATORS(LineGLFlags) |
||||
} |
||||
#endif |
||||
|
||||
}} |
||||
|
||||
#endif |
||||
@ -0,0 +1,754 @@
|
||||
/*
|
||||
This file is part of Magnum. |
||||
|
||||
Copyright © 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019, |
||||
2020, 2021, 2022 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. |
||||
*/ |
||||
|
||||
#include <sstream> |
||||
#include <Corrade/Containers/StridedArrayView.h> |
||||
#include <Corrade/PluginManager/Manager.h> |
||||
#include <Corrade/Utility/DebugStl.h> |
||||
#include <Corrade/Utility/FormatStl.h> |
||||
#include <Corrade/Utility/Path.h> |
||||
#include <Corrade/Utility/System.h> |
||||
|
||||
#include "Magnum/Image.h" |
||||
#include "Magnum/PixelFormat.h" |
||||
#include "Magnum/DebugTools/CompareImage.h" |
||||
#include "Magnum/GL/Buffer.h" |
||||
#include "Magnum/GL/Extensions.h" |
||||
#include "Magnum/GL/Framebuffer.h" |
||||
#include "Magnum/GL/Mesh.h" |
||||
#include "Magnum/GL/OpenGLTester.h" |
||||
#include "Magnum/GL/Renderbuffer.h" |
||||
#include "Magnum/GL/RenderbufferFormat.h" |
||||
#include "Magnum/Math/Color.h" |
||||
#include "Magnum/Math/Matrix3.h" |
||||
#include "Magnum/Math/Matrix4.h" |
||||
#include "Magnum/Shaders/Generic.h" |
||||
#include "Magnum/Shaders/Line.h" |
||||
#include "Magnum/Shaders/LineGL.h" |
||||
#include "Magnum/Trade/AbstractImporter.h" |
||||
|
||||
#include "configure.h" |
||||
|
||||
namespace Magnum { namespace Shaders { namespace Test { namespace { |
||||
|
||||
struct LineGLTest: GL::OpenGLTester { |
||||
explicit LineGLTest(); |
||||
|
||||
template<UnsignedInt dimensions> void construct(); |
||||
template<UnsignedInt dimensions> void constructAsync(); |
||||
#ifndef MAGNUM_TARGET_GLES2 |
||||
template<UnsignedInt dimensions> void constructUniformBuffers(); |
||||
template<UnsignedInt dimensions> void constructUniformBuffersAsync(); |
||||
#endif |
||||
|
||||
template<UnsignedInt dimensions> void constructMove(); |
||||
#ifndef MAGNUM_TARGET_GLES2 |
||||
template<UnsignedInt dimensions> void constructMoveUniformBuffers(); |
||||
#endif |
||||
|
||||
// template<UnsignedInt dimensions> void constructInvalid();
|
||||
#ifndef MAGNUM_TARGET_GLES2 |
||||
template<UnsignedInt dimensions> void constructUniformBuffersInvalid(); |
||||
#endif |
||||
|
||||
#ifndef MAGNUM_TARGET_GLES2 |
||||
template<UnsignedInt dimensions> void setUniformUniformBuffersEnabled(); |
||||
template<UnsignedInt dimensions> void bindBufferUniformBuffersNotEnabled(); |
||||
#endif |
||||
#ifndef MAGNUM_TARGET_GLES2 |
||||
template<UnsignedInt dimensions> void setObjectIdNotEnabled(); |
||||
#endif |
||||
#ifndef MAGNUM_TARGET_GLES2 |
||||
template<UnsignedInt dimensions> void setWrongDrawOffset(); |
||||
#endif |
||||
|
||||
void renderSetup(); |
||||
void renderTeardown(); |
||||
|
||||
template<LineGL2D::Flag flag = LineGL2D::Flag{}> void renderDefaults2D(); |
||||
template<LineGL3D::Flag flag = LineGL3D::Flag{}> void renderDefaults3D(); |
||||
|
||||
template<LineGL2D::Flag flag = LineGL2D::Flag{}> void render2D(); |
||||
template<LineGL3D::Flag flag = LineGL3D::Flag{}> void render3D(); |
||||
|
||||
template<class T, LineGL2D::Flag flag = LineGL2D::Flag{}> void renderVertexColor2D(); |
||||
template<class T, LineGL3D::Flag flag = LineGL3D::Flag{}> void renderVertexColor3D(); |
||||
|
||||
#ifndef MAGNUM_TARGET_GLES2 |
||||
void renderObjectIdSetup(); |
||||
void renderObjectIdTeardown(); |
||||
|
||||
template<LineGL2D::Flag flag = LineGL2D::Flag{}> void renderObjectId2D(); |
||||
template<LineGL3D::Flag flag = LineGL3D::Flag{}> void renderObjectId3D(); |
||||
#endif |
||||
|
||||
template<LineGL2D::Flag flag = LineGL2D::Flag{}> void renderInstanced2D(); |
||||
template<LineGL3D::Flag flag = LineGL3D::Flag{}> void renderInstanced3D(); |
||||
|
||||
#ifndef MAGNUM_TARGET_GLES2 |
||||
void renderMulti2D(); |
||||
void renderMulti3D(); |
||||
#endif |
||||
|
||||
private: |
||||
PluginManager::Manager<Trade::AbstractImporter> _manager{"nonexistent"}; |
||||
Containers::String _testDir; |
||||
|
||||
GL::Renderbuffer _color{NoCreate}; |
||||
#ifndef MAGNUM_TARGET_GLES2 |
||||
GL::Renderbuffer _objectId{NoCreate}; |
||||
#endif |
||||
GL::Framebuffer _framebuffer{NoCreate}; |
||||
}; |
||||
|
||||
using namespace Math::Literals; |
||||
|
||||
const struct { |
||||
const char* name; |
||||
LineGL2D::Flags flags; |
||||
} ConstructData[]{ |
||||
{"", {}}, |
||||
{"vertex colors", LineGL2D::Flag::VertexColor}, |
||||
#ifndef MAGNUM_TARGET_GLES2 |
||||
{"object ID", LineGL2D::Flag::ObjectId}, |
||||
{"instanced object ID", LineGL2D::Flag::InstancedObjectId}, |
||||
#endif |
||||
{"instanced transformation", LineGL2D::Flag::InstancedTransformation}, |
||||
}; |
||||
|
||||
#ifndef MAGNUM_TARGET_GLES2 |
||||
const struct { |
||||
const char* name; |
||||
LineGL2D::Flags flags; |
||||
UnsignedInt materialCount, drawCount; |
||||
} ConstructUniformBuffersData[]{ |
||||
{"classic fallback", {}, 1, 1}, |
||||
{"", LineGL2D::Flag::UniformBuffers, 1, 1}, |
||||
/* SwiftShader has 256 uniform vectors at most, per-draw is 4+1 in 3D case
|
||||
and 3+1 in 2D, per-material 1 */ |
||||
{"multiple materials, draws", LineGL2D::Flag::UniformBuffers, 16, 48}, |
||||
{"object ID", LineGL2D::Flag::UniformBuffers|LineGL2D::Flag::ObjectId, 1, 1}, |
||||
{"instanced object ID", LineGL2D::Flag::UniformBuffers|LineGL2D::Flag::InstancedObjectId, 1, 1}, |
||||
{"multidraw with all the things", LineGL2D::Flag::MultiDraw|LineGL2D::Flag::ObjectId|LineGL2D::Flag::InstancedTransformation|LineGL2D::Flag::InstancedObjectId, 16, 48} |
||||
}; |
||||
#endif |
||||
|
||||
// const struct {
|
||||
// const char* name;
|
||||
// LineGL2D::Flags flags;
|
||||
// const char* message;
|
||||
// } ConstructInvalidData[]{
|
||||
// };
|
||||
|
||||
#ifndef MAGNUM_TARGET_GLES2 |
||||
constexpr struct { |
||||
const char* name; |
||||
LineGL2D::Flags flags; |
||||
UnsignedInt materialCount, drawCount; |
||||
const char* message; |
||||
} ConstructUniformBuffersInvalidData[]{ |
||||
{"zero draws", LineGL2D::Flag::UniformBuffers, 1, 0, |
||||
"draw count can't be zero"}, |
||||
{"zero materials", LineGL2D::Flag::UniformBuffers, 0, 1, |
||||
"material count can't be zero"} |
||||
}; |
||||
#endif |
||||
|
||||
LineGLTest::LineGLTest() { |
||||
addInstancedTests<LineGLTest>({ |
||||
&LineGLTest::construct<2>, |
||||
// &LineGLTest::construct<3>
|
||||
|
||||
}, |
||||
Containers::arraySize(ConstructData)); |
||||
|
||||
addTests<LineGLTest>({ |
||||
&LineGLTest::constructAsync<2>, |
||||
// &LineGLTest::constructAsync<3>
|
||||
|
||||
}); |
||||
|
||||
#ifndef MAGNUM_TARGET_GLES2 |
||||
// addInstancedTests<LineGLTest>({
|
||||
// &LineGLTest::constructUniformBuffers<2>,
|
||||
// &LineGLTest::constructUniformBuffers<3>},
|
||||
// Containers::arraySize(ConstructUniformBuffersData));
|
||||
//
|
||||
// addTests<LineGLTest>({
|
||||
// &LineGLTest::constructUniformBuffersAsync<2>,
|
||||
// &LineGLTest::constructUniformBuffersAsync<3>});
|
||||
#endif |
||||
|
||||
addTests<LineGLTest>({ |
||||
&LineGLTest::constructMove<2>, |
||||
// &LineGLTest::constructMove<3>,
|
||||
|
||||
// #ifndef MAGNUM_TARGET_GLES2
|
||||
// &LineGLTest::constructMoveUniformBuffers<2>,
|
||||
// &LineGLTest::constructMoveUniformBuffers<3>,
|
||||
// #endif
|
||||
}); |
||||
|
||||
// addInstancedTests<LineGLTest>({
|
||||
// &LineGLTest::constructInvalid<2>,
|
||||
// &LineGLTest::constructInvalid<3>},
|
||||
// Containers::arraySize(ConstructInvalidData));
|
||||
|
||||
#ifndef MAGNUM_TARGET_GLES2 |
||||
addInstancedTests<LineGLTest>({ |
||||
&LineGLTest::constructUniformBuffersInvalid<2>, |
||||
// &LineGLTest::constructUniformBuffersInvalid<3>
|
||||
|
||||
}, |
||||
Containers::arraySize(ConstructUniformBuffersInvalidData)); |
||||
#endif |
||||
|
||||
#ifndef MAGNUM_TARGET_GLES2 |
||||
addTests<LineGLTest>({ |
||||
// &LineGLTest::setUniformUniformBuffersEnabled<2>,
|
||||
// &LineGLTest::setUniformUniformBuffersEnabled<3>,
|
||||
&LineGLTest::bindBufferUniformBuffersNotEnabled<2>, |
||||
// &LineGLTest::bindBufferUniformBuffersNotEnabled<3>,
|
||||
&LineGLTest::setObjectIdNotEnabled<2>, |
||||
// &LineGLTest::setObjectIdNotEnabled<3>,
|
||||
// &LineGLTest::setWrongDrawOffset<2>,
|
||||
// &LineGLTest::setWrongDrawOffset<3>
|
||||
|
||||
}); |
||||
#endif |
||||
|
||||
/* MSVC needs explicit type due to default template args */ |
||||
addTests<LineGLTest>({ |
||||
&LineGLTest::renderDefaults2D, |
||||
#ifndef MAGNUM_TARGET_GLES2 |
||||
// &LineGLTest::renderDefaults2D<LineGL2D::Flag::UniformBuffers>,
|
||||
#endif |
||||
// &LineGLTest::renderDefaults3D,
|
||||
// #ifndef MAGNUM_TARGET_GLES2
|
||||
// &LineGLTest::renderDefaults3D<LineGL3D::Flag::UniformBuffers>,
|
||||
// #endif
|
||||
}, |
||||
&LineGLTest::renderSetup, |
||||
&LineGLTest::renderTeardown); |
||||
|
||||
/* Load the plugins directly from the build tree. Otherwise they're either
|
||||
static and already loaded or not present in the build tree */ |
||||
#ifdef ANYIMAGEIMPORTER_PLUGIN_FILENAME |
||||
CORRADE_INTERNAL_ASSERT_OUTPUT(_manager.load(ANYIMAGEIMPORTER_PLUGIN_FILENAME) & PluginManager::LoadState::Loaded); |
||||
#endif |
||||
#ifdef TGAIMPORTER_PLUGIN_FILENAME |
||||
CORRADE_INTERNAL_ASSERT_OUTPUT(_manager.load(TGAIMPORTER_PLUGIN_FILENAME) & PluginManager::LoadState::Loaded); |
||||
#endif |
||||
} |
||||
|
||||
template<UnsignedInt dimensions> void LineGLTest::construct() { |
||||
setTestCaseTemplateName(Utility::format("{}", dimensions)); |
||||
|
||||
auto&& data = ConstructData[testCaseInstanceId()]; |
||||
setTestCaseDescription(data.name); |
||||
|
||||
#ifndef MAGNUM_TARGET_GLES |
||||
if((data.flags & LineGL2D::Flag::ObjectId) && !GL::Context::current().isExtensionSupported<GL::Extensions::EXT::gpu_shader4>()) |
||||
CORRADE_SKIP(GL::Extensions::EXT::gpu_shader4::string() << "is not supported."); |
||||
#endif |
||||
|
||||
LineGL<dimensions> shader{typename LineGL<dimensions>::Configuration{} |
||||
.setFlags(data.flags)}; |
||||
CORRADE_COMPARE(shader.flags(), data.flags); |
||||
CORRADE_VERIFY(shader.id()); |
||||
{ |
||||
#if defined(CORRADE_TARGET_APPLE) && !defined(MAGNUM_TARGET_GLES) |
||||
CORRADE_EXPECT_FAIL("macOS drivers need insane amount of state to validate properly."); |
||||
#endif |
||||
CORRADE_VERIFY(shader.validate().first); |
||||
} |
||||
|
||||
MAGNUM_VERIFY_NO_GL_ERROR(); |
||||
} |
||||
|
||||
template<UnsignedInt dimensions> void LineGLTest::constructAsync() { |
||||
setTestCaseTemplateName(Utility::format("{}", dimensions)); |
||||
|
||||
typename LineGL<dimensions>::CompileState state = LineGL<dimensions>::compile(typename LineGL<dimensions>::Configuration{} |
||||
.setFlags(LineGL2D::Flag::VertexColor)); |
||||
CORRADE_COMPARE(state.flags(), LineGL2D::Flag::VertexColor); |
||||
|
||||
while(!state.isLinkFinished()) |
||||
Utility::System::sleep(100); |
||||
|
||||
LineGL<dimensions> shader{std::move(state)}; |
||||
CORRADE_COMPARE(shader.flags(), LineGL2D::Flag::VertexColor); |
||||
|
||||
CORRADE_VERIFY(shader.id()); |
||||
{ |
||||
#if defined(CORRADE_TARGET_APPLE) && !defined(MAGNUM_TARGET_GLES) |
||||
CORRADE_EXPECT_FAIL("macOS drivers need insane amount of state to validate properly."); |
||||
#endif |
||||
CORRADE_VERIFY(shader.validate().first); |
||||
} |
||||
|
||||
MAGNUM_VERIFY_NO_GL_ERROR(); |
||||
} |
||||
|
||||
#ifndef MAGNUM_TARGET_GLES2 |
||||
template<UnsignedInt dimensions> void LineGLTest::constructUniformBuffers() { |
||||
setTestCaseTemplateName(Utility::format("{}", dimensions)); |
||||
|
||||
auto&& data = ConstructUniformBuffersData[testCaseInstanceId()]; |
||||
setTestCaseDescription(data.name); |
||||
|
||||
#ifndef MAGNUM_TARGET_GLES |
||||
if((data.flags & LineGL2D::Flag::UniformBuffers) && !GL::Context::current().isExtensionSupported<GL::Extensions::ARB::uniform_buffer_object>()) |
||||
CORRADE_SKIP(GL::Extensions::ARB::uniform_buffer_object::string() << "is not supported."); |
||||
if((data.flags & LineGL2D::Flag::ObjectId) && !GL::Context::current().isExtensionSupported<GL::Extensions::EXT::gpu_shader4>()) |
||||
CORRADE_SKIP(GL::Extensions::EXT::gpu_shader4::string() << "is not supported."); |
||||
#endif |
||||
|
||||
if(data.flags >= LineGL2D::Flag::MultiDraw) { |
||||
#ifndef MAGNUM_TARGET_GLES |
||||
if(!GL::Context::current().isExtensionSupported<GL::Extensions::ARB::shader_draw_parameters>()) |
||||
CORRADE_SKIP(GL::Extensions::ARB::shader_draw_parameters::string() << "is not supported."); |
||||
#elif !defined(MAGNUM_TARGET_WEBGL) |
||||
if(!GL::Context::current().isExtensionSupported<GL::Extensions::ANGLE::multi_draw>()) |
||||
CORRADE_SKIP(GL::Extensions::ANGLE::multi_draw::string() << "is not supported."); |
||||
#else |
||||
if(!GL::Context::current().isExtensionSupported<GL::Extensions::WEBGL::multi_draw>()) |
||||
CORRADE_SKIP(GL::Extensions::WEBGL::multi_draw::string() << "is not supported."); |
||||
#endif |
||||
} |
||||
|
||||
LineGL<dimensions> shader{typename LineGL<dimensions>::Configuration{} |
||||
.setFlags(data.flags) |
||||
.setMaterialCount(data.materialCount) |
||||
.setDrawCount(data.drawCount)}; |
||||
CORRADE_COMPARE(shader.flags(), data.flags); |
||||
CORRADE_COMPARE(shader.materialCount(), data.materialCount); |
||||
CORRADE_COMPARE(shader.drawCount(), data.drawCount); |
||||
CORRADE_VERIFY(shader.id()); |
||||
{ |
||||
#if defined(CORRADE_TARGET_APPLE) && !defined(MAGNUM_TARGET_GLES) |
||||
CORRADE_EXPECT_FAIL("macOS drivers need insane amount of state to validate properly."); |
||||
#endif |
||||
CORRADE_VERIFY(shader.validate().first); |
||||
} |
||||
|
||||
MAGNUM_VERIFY_NO_GL_ERROR(); |
||||
} |
||||
|
||||
template<UnsignedInt dimensions> void LineGLTest::constructUniformBuffersAsync() { |
||||
setTestCaseTemplateName(Utility::format("{}", dimensions)); |
||||
|
||||
#ifndef MAGNUM_TARGET_GLES |
||||
if(!GL::Context::current().isExtensionSupported<GL::Extensions::ARB::uniform_buffer_object>()) |
||||
CORRADE_SKIP(GL::Extensions::ARB::uniform_buffer_object::string() << "is not supported."); |
||||
#endif |
||||
|
||||
typename LineGL<dimensions>::CompileState state = LineGL<dimensions>::compile(typename LineGL<dimensions>::Configuration{} |
||||
.setFlags(LineGL2D::Flag::UniformBuffers|LineGL2D::Flag::VertexColor) |
||||
.setMaterialCount(16) |
||||
.setDrawCount(48)); |
||||
CORRADE_COMPARE(state.flags(), LineGL2D::Flag::UniformBuffers|LineGL2D::Flag::VertexColor); |
||||
CORRADE_COMPARE(state.materialCount(), 16); |
||||
CORRADE_COMPARE(state.drawCount(), 48); |
||||
|
||||
while(!state.isLinkFinished()) |
||||
Utility::System::sleep(100); |
||||
|
||||
LineGL<dimensions> shader{std::move(state)}; |
||||
CORRADE_COMPARE(shader.flags(), LineGL2D::Flag::UniformBuffers|LineGL2D::Flag::VertexColor); |
||||
CORRADE_COMPARE(shader.materialCount(), 16); |
||||
CORRADE_COMPARE(shader.drawCount(), 48); |
||||
CORRADE_VERIFY(shader.id()); |
||||
{ |
||||
#if defined(CORRADE_TARGET_APPLE) && !defined(MAGNUM_TARGET_GLES) |
||||
CORRADE_EXPECT_FAIL("macOS drivers need insane amount of state to validate properly."); |
||||
#endif |
||||
CORRADE_VERIFY(shader.validate().first); |
||||
} |
||||
|
||||
MAGNUM_VERIFY_NO_GL_ERROR(); |
||||
} |
||||
|
||||
#endif |
||||
|
||||
template<UnsignedInt dimensions> void LineGLTest::constructMove() { |
||||
setTestCaseTemplateName(Utility::format("{}", dimensions)); |
||||
|
||||
LineGL<dimensions> a{typename LineGL<dimensions>::Configuration{} |
||||
.setFlags(LineGL<dimensions>::Flag::VertexColor)}; |
||||
const GLuint id = a.id(); |
||||
CORRADE_VERIFY(id); |
||||
|
||||
MAGNUM_VERIFY_NO_GL_ERROR(); |
||||
|
||||
LineGL<dimensions> b{std::move(a)}; |
||||
CORRADE_COMPARE(b.id(), id); |
||||
CORRADE_COMPARE(b.flags(), LineGL<dimensions>::Flag::VertexColor); |
||||
CORRADE_VERIFY(!a.id()); |
||||
|
||||
LineGL<dimensions> c{NoCreate}; |
||||
c = std::move(b); |
||||
CORRADE_COMPARE(c.id(), id); |
||||
CORRADE_COMPARE(c.flags(), LineGL<dimensions>::Flag::VertexColor); |
||||
CORRADE_VERIFY(!b.id()); |
||||
} |
||||
|
||||
#ifndef MAGNUM_TARGET_GLES2 |
||||
template<UnsignedInt dimensions> void LineGLTest::constructMoveUniformBuffers() { |
||||
setTestCaseTemplateName(Utility::format("{}", dimensions)); |
||||
|
||||
#ifndef MAGNUM_TARGET_GLES |
||||
if(!GL::Context::current().isExtensionSupported<GL::Extensions::ARB::uniform_buffer_object>()) |
||||
CORRADE_SKIP(GL::Extensions::ARB::uniform_buffer_object::string() << "is not supported."); |
||||
#endif |
||||
|
||||
LineGL<dimensions> a{typename LineGL<dimensions>::Configuration{} |
||||
.setFlags(LineGL<dimensions>::Flag::UniformBuffers) |
||||
.setMaterialCount(2) |
||||
.setDrawCount(5)}; |
||||
const GLuint id = a.id(); |
||||
CORRADE_VERIFY(id); |
||||
|
||||
MAGNUM_VERIFY_NO_GL_ERROR(); |
||||
|
||||
LineGL<dimensions> b{std::move(a)}; |
||||
CORRADE_COMPARE(b.id(), id); |
||||
CORRADE_COMPARE(b.flags(), LineGL<dimensions>::Flag::UniformBuffers); |
||||
CORRADE_COMPARE(b.materialCount(), 2); |
||||
CORRADE_COMPARE(b.drawCount(), 5); |
||||
CORRADE_VERIFY(!a.id()); |
||||
|
||||
LineGL<dimensions> c{NoCreate}; |
||||
c = std::move(b); |
||||
CORRADE_COMPARE(c.id(), id); |
||||
CORRADE_COMPARE(c.flags(), LineGL<dimensions>::Flag::UniformBuffers); |
||||
CORRADE_COMPARE(c.materialCount(), 2); |
||||
CORRADE_COMPARE(c.drawCount(), 5); |
||||
CORRADE_VERIFY(!b.id()); |
||||
} |
||||
#endif |
||||
|
||||
// template<UnsignedInt dimensions> void LineGLTest::constructInvalid() {
|
||||
// auto&& data = ConstructInvalidData[testCaseInstanceId()];
|
||||
// setTestCaseTemplateName(Utility::format("{}", dimensions));
|
||||
// setTestCaseDescription(data.name);
|
||||
//
|
||||
// CORRADE_SKIP_IF_NO_ASSERT();
|
||||
//
|
||||
// std::ostringstream out;
|
||||
// Error redirectError{&out};
|
||||
// LineGL<dimensions>{data.flags};
|
||||
// CORRADE_COMPARE(out.str(), Utility::formatString(
|
||||
// "Shaders::LineGL: {}\n", data.message));
|
||||
// }
|
||||
|
||||
#ifndef MAGNUM_TARGET_GLES2 |
||||
template<UnsignedInt dimensions> void LineGLTest::constructUniformBuffersInvalid() { |
||||
auto&& data = ConstructUniformBuffersInvalidData[testCaseInstanceId()]; |
||||
setTestCaseTemplateName(Utility::format("{}", dimensions)); |
||||
setTestCaseDescription(data.name); |
||||
|
||||
CORRADE_SKIP_IF_NO_ASSERT(); |
||||
|
||||
#ifndef MAGNUM_TARGET_GLES |
||||
if(!GL::Context::current().isExtensionSupported<GL::Extensions::ARB::uniform_buffer_object>()) |
||||
CORRADE_SKIP(GL::Extensions::ARB::uniform_buffer_object::string() << "is not supported."); |
||||
#endif |
||||
|
||||
std::ostringstream out; |
||||
Error redirectError{&out}; |
||||
LineGL<dimensions>{typename LineGL<dimensions>::Configuration{} |
||||
.setFlags(data.flags) |
||||
.setMaterialCount(data.materialCount) |
||||
.setDrawCount(data.drawCount)}; |
||||
CORRADE_COMPARE(out.str(), Utility::formatString( |
||||
"Shaders::LineGL: {}\n", data.message)); |
||||
} |
||||
#endif |
||||
|
||||
#ifndef MAGNUM_TARGET_GLES2 |
||||
template<UnsignedInt dimensions> void LineGLTest::setUniformUniformBuffersEnabled() { |
||||
setTestCaseTemplateName(Utility::format("{}", dimensions)); |
||||
|
||||
CORRADE_SKIP_IF_NO_ASSERT(); |
||||
|
||||
#ifndef MAGNUM_TARGET_GLES |
||||
if(!GL::Context::current().isExtensionSupported<GL::Extensions::ARB::uniform_buffer_object>()) |
||||
CORRADE_SKIP(GL::Extensions::ARB::uniform_buffer_object::string() << "is not supported."); |
||||
#endif |
||||
|
||||
LineGL<dimensions> shader{typename LineGL<dimensions>::Configuration{} |
||||
.setFlags(LineGL<dimensions>::Flag::UniformBuffers)}; |
||||
|
||||
/* This should work fine */ |
||||
shader.setViewportSize({}); |
||||
|
||||
std::ostringstream out; |
||||
Error redirectError{&out}; |
||||
shader.setTransformationProjectionMatrix({}) |
||||
.setWidth({}) |
||||
.setSmoothness({}) |
||||
.setBackgroundColor({}) |
||||
.setColor({}) |
||||
.setObjectId({}); |
||||
CORRADE_COMPARE(out.str(), |
||||
"Shaders::LineGL::setTransformationProjectionMatrix(): the shader was created with uniform buffers enabled\n" |
||||
"Shaders::LineGL::setWidth(): the shader was created with uniform buffers enabled\n" |
||||
"Shaders::LineGL::setSmoothness(): the shader was created with uniform buffers enabled\n" |
||||
"Shaders::LineGL::setBackgroundColor(): the shader was created with uniform buffers enabled\n" |
||||
"Shaders::LineGL::setColor(): the shader was created with uniform buffers enabled\n" |
||||
"Shaders::LineGL::setObjectId(): the shader was created with uniform buffers enabled\n"); |
||||
} |
||||
|
||||
template<UnsignedInt dimensions> void LineGLTest::bindBufferUniformBuffersNotEnabled() { |
||||
setTestCaseTemplateName(Utility::format("{}", dimensions)); |
||||
|
||||
CORRADE_SKIP_IF_NO_ASSERT(); |
||||
|
||||
std::ostringstream out; |
||||
Error redirectError{&out}; |
||||
|
||||
GL::Buffer buffer; |
||||
LineGL<dimensions> shader; |
||||
shader.bindTransformationProjectionBuffer(buffer) |
||||
.bindTransformationProjectionBuffer(buffer, 0, 16) |
||||
.bindDrawBuffer(buffer) |
||||
.bindDrawBuffer(buffer, 0, 16) |
||||
.bindMaterialBuffer(buffer) |
||||
.bindMaterialBuffer(buffer, 0, 16) |
||||
.setDrawOffset(0); |
||||
CORRADE_COMPARE(out.str(), |
||||
"Shaders::LineGL::bindTransformationProjectionBuffer(): the shader was not created with uniform buffers enabled\n" |
||||
"Shaders::LineGL::bindTransformationProjectionBuffer(): the shader was not created with uniform buffers enabled\n" |
||||
"Shaders::LineGL::bindDrawBuffer(): the shader was not created with uniform buffers enabled\n" |
||||
"Shaders::LineGL::bindDrawBuffer(): the shader was not created with uniform buffers enabled\n" |
||||
"Shaders::LineGL::bindMaterialBuffer(): the shader was not created with uniform buffers enabled\n" |
||||
"Shaders::LineGL::bindMaterialBuffer(): the shader was not created with uniform buffers enabled\n" |
||||
"Shaders::LineGL::setDrawOffset(): the shader was not created with uniform buffers enabled\n"); |
||||
} |
||||
#endif |
||||
|
||||
#ifndef MAGNUM_TARGET_GLES2 |
||||
template<UnsignedInt dimensions> void LineGLTest::setObjectIdNotEnabled() { |
||||
setTestCaseTemplateName(Utility::format("{}", dimensions)); |
||||
|
||||
CORRADE_SKIP_IF_NO_ASSERT(); |
||||
|
||||
LineGL<dimensions> shader; |
||||
|
||||
std::ostringstream out; |
||||
Error redirectError{&out}; |
||||
shader.setObjectId(33376); |
||||
CORRADE_COMPARE(out.str(), |
||||
"Shaders::LineGL::setObjectId(): the shader was not created with object ID enabled\n"); |
||||
} |
||||
#endif |
||||
|
||||
#ifndef MAGNUM_TARGET_GLES2 |
||||
template<UnsignedInt dimensions> void LineGLTest::setWrongDrawOffset() { |
||||
setTestCaseTemplateName(Utility::format("{}", dimensions)); |
||||
|
||||
CORRADE_SKIP_IF_NO_ASSERT(); |
||||
|
||||
#ifndef MAGNUM_TARGET_GLES |
||||
if(!GL::Context::current().isExtensionSupported<GL::Extensions::ARB::uniform_buffer_object>()) |
||||
CORRADE_SKIP(GL::Extensions::ARB::uniform_buffer_object::string() << "is not supported."); |
||||
#endif |
||||
|
||||
LineGL<dimensions> shader{typename LineGL<dimensions>::Configuration{} |
||||
.setFlags(LineGL<dimensions>::Flag::UniformBuffers) |
||||
.setMaterialCount(2) |
||||
.setDrawCount(5)}; |
||||
|
||||
std::ostringstream out; |
||||
Error redirectError{&out}; |
||||
shader.setDrawOffset(5); |
||||
CORRADE_COMPARE(out.str(), |
||||
"Shaders::LineGL::setDrawOffset(): draw offset 5 is out of bounds for 5 draws\n"); |
||||
} |
||||
#endif |
||||
|
||||
constexpr Vector2i RenderSize{80, 80}; |
||||
|
||||
void LineGLTest::renderSetup() { |
||||
/* Pick a color that's directly representable on RGBA4 as well to reduce
|
||||
artifacts */ |
||||
GL::Renderer::setClearColor(0x111111_rgbf); |
||||
GL::Renderer::enable(GL::Renderer::Feature::FaceCulling); |
||||
|
||||
_color = GL::Renderbuffer{}; |
||||
_color.setStorage( |
||||
#if !defined(MAGNUM_TARGET_GLES2) || !defined(MAGNUM_TARGET_WEBGL) |
||||
GL::RenderbufferFormat::RGBA8, |
||||
#else |
||||
GL::RenderbufferFormat::RGBA4, |
||||
#endif |
||||
RenderSize); |
||||
_framebuffer = GL::Framebuffer{{{}, RenderSize}}; |
||||
_framebuffer.attachRenderbuffer(GL::Framebuffer::ColorAttachment{0}, _color) |
||||
.clear(GL::FramebufferClear::Color) |
||||
.bind(); |
||||
} |
||||
|
||||
void LineGLTest::renderTeardown() { |
||||
_framebuffer = GL::Framebuffer{NoCreate}; |
||||
_color = GL::Renderbuffer{NoCreate}; |
||||
} |
||||
|
||||
template<LineGL2D::Flag flag> void LineGLTest::renderDefaults2D() { |
||||
#ifndef MAGNUM_TARGET_GLES2 |
||||
if(flag == LineGL2D::Flag::UniformBuffers) { |
||||
setTestCaseTemplateName("Flag::UniformBuffers"); |
||||
|
||||
#ifndef MAGNUM_TARGET_GLES |
||||
if(!GL::Context::current().isExtensionSupported<GL::Extensions::ARB::uniform_buffer_object>()) |
||||
CORRADE_SKIP(GL::Extensions::ARB::uniform_buffer_object::string() << "is not supported."); |
||||
#endif |
||||
} |
||||
#endif |
||||
|
||||
// TODO drop this crap, use MeshTools once things settle down
|
||||
struct Vertex { |
||||
Vector2 neighborDirection; |
||||
Vector2 position; |
||||
Vector2 direction; |
||||
} vertices[]{ |
||||
/* Two connected line segments, down and then to the right */ |
||||
{Vector2{Constants::nan()}, {-0.25f, 0.5f}, {}}, |
||||
{Vector2{Constants::nan()}, {-0.25f, 0.5f}, {}}, |
||||
{{}, {-0.5f, -0.5f}, {}}, |
||||
{{}, {-0.5f, -0.5f}, {}}, |
||||
{{}, {-0.5f, -0.5f}, {}}, |
||||
{{}, {-0.5f, -0.5f}, {}}, |
||||
{Vector2{Constants::nan()}, {0.5f, -0.25f}, {}}, |
||||
{Vector2{Constants::nan()}, {0.5f, -0.25f}, {}}, |
||||
|
||||
/* Singular horizontal and vertical segment */ |
||||
{Vector2{Constants::nan()}, {-0.75f, 0.25f}, {}}, |
||||
{Vector2{Constants::nan()}, {-0.75f, 0.25f}, {}}, |
||||
{Vector2{Constants::nan()}, {-0.75f, 0.75f}, {}}, |
||||
{Vector2{Constants::nan()}, {-0.75f, 0.75f}, {}}, |
||||
|
||||
{Vector2{Constants::nan()}, {-0.25f, -0.75f}, {}}, |
||||
{Vector2{Constants::nan()}, {-0.25f, -0.75f}, {}}, |
||||
{Vector2{Constants::nan()}, {0.75f, -0.75f}, {}}, |
||||
{Vector2{Constants::nan()}, {0.75f, -0.75f}, {}}, |
||||
|
||||
/* A single point */ |
||||
{Vector2{Constants::nan()}, {0.5f, 0.5f}, {}}, |
||||
{Vector2{Constants::nan()}, {0.5f, 0.5f}, {}}, |
||||
{Vector2{Constants::nan()}, {0.5f, 0.5f}, {}}, |
||||
{Vector2{Constants::nan()}, {0.5f, 0.5f}, {}}, |
||||
}; |
||||
|
||||
/* Prev directions */ |
||||
for(std::size_t i = 4; i < Containers::arraySize(vertices); i += 4) { |
||||
if(Math::isNan(vertices[i + 0].neighborDirection)) continue; |
||||
vertices[i + 0].neighborDirection = vertices[i + 1].neighborDirection = |
||||
vertices[i - 4].position - vertices[i + 0].position; |
||||
} |
||||
/* Segment directions */ |
||||
for(std::size_t i = 0; i < Containers::arraySize(vertices); i += 4) { |
||||
vertices[i + 0].direction = vertices[i + 1].direction = |
||||
vertices[i + 2].direction = vertices[i + 3].direction = |
||||
vertices[i + 2].position - vertices[i + 0].position; |
||||
} |
||||
/* Next directions */ |
||||
for(std::size_t i = 2; i < Containers::arraySize(vertices) - 4; i += 4) { |
||||
if(Math::isNan(vertices[i + 0].neighborDirection)) continue; |
||||
vertices[i + 0].neighborDirection = vertices[i + 1].neighborDirection = |
||||
vertices[i + 4].position - vertices[i + 0].position; |
||||
} |
||||
|
||||
!Debug{} << Containers::stridedArrayView(vertices).slice(&Vertex::position).prefix(8); |
||||
!Debug{} << Containers::stridedArrayView(vertices).slice(&Vertex::direction).prefix(8); |
||||
!Debug{} << Containers::stridedArrayView(vertices).slice(&Vertex::neighborDirection).prefix(8); |
||||
|
||||
const UnsignedInt indices[]{ |
||||
0, 1, 2, 2, 1, 3, |
||||
4, 5, 6, 6, 5, 7, |
||||
8, 9, 10, 10, 9, 11, |
||||
12, 13, 14, 14, 13, 15, |
||||
16, 17, 18, 18, 17, 19 |
||||
}; |
||||
|
||||
GL::Mesh lines; |
||||
lines.addVertexBuffer(GL::Buffer{vertices}, 0, |
||||
LineGL2D::LineNeighborDirection{}, |
||||
LineGL2D::Position{}, |
||||
LineGL2D::LineDirection{}) |
||||
.setIndexBuffer(GL::Buffer{indices}, 0, GL::MeshIndexType::UnsignedInt) |
||||
.setCount(Containers::arraySize(indices)); |
||||
|
||||
LineGL2D shader{LineGL2D::Configuration{} |
||||
.setFlags(flag)}; |
||||
shader.setViewportSize(Vector2{RenderSize}); |
||||
shader |
||||
.setWidth(5.0f) |
||||
.setSmoothness(1.0f) |
||||
// .setBackgroundColor(0xff0000ff_rgbaf)
|
||||
// .setColor(0x557766_rgbf)
|
||||
; |
||||
|
||||
if(flag == LineGL2D::Flag{}) { |
||||
shader.draw(lines); |
||||
} |
||||
#ifndef MAGNUM_TARGET_GLES2 |
||||
else if(flag == LineGL2D::Flag::UniformBuffers) { |
||||
GL::Buffer transformationProjectionUniform{GL::Buffer::TargetHint::Uniform, { |
||||
TransformationProjectionUniform2D{} |
||||
}}; |
||||
GL::Buffer drawUniform{GL::Buffer::TargetHint::Uniform, { |
||||
LineDrawUniform{} |
||||
}}; |
||||
GL::Buffer materialUniform{GL::Buffer::TargetHint::Uniform, { |
||||
LineMaterialUniform{} |
||||
}}; |
||||
shader |
||||
.bindTransformationProjectionBuffer(transformationProjectionUniform) |
||||
.bindDrawBuffer(drawUniform) |
||||
.bindMaterialBuffer(materialUniform) |
||||
.draw(lines); |
||||
} |
||||
#endif |
||||
else CORRADE_INTERNAL_ASSERT_UNREACHABLE(); |
||||
|
||||
MAGNUM_VERIFY_NO_GL_ERROR(); |
||||
|
||||
if(!(_manager.loadState("AnyImageImporter") & PluginManager::LoadState::Loaded) || |
||||
!(_manager.loadState("TgaImporter") & PluginManager::LoadState::Loaded)) |
||||
CORRADE_SKIP("AnyImageImporter / TgaImporter plugins not found."); |
||||
|
||||
CORRADE_COMPARE_WITH( |
||||
/* Dropping the alpha channel, as it's always 1.0 */ |
||||
Containers::arrayCast<Color3ub>(_framebuffer.read(_framebuffer.viewport(), {PixelFormat::RGBA8Unorm}).pixels<Color4ub>()), |
||||
Utility::Path::join(_testDir, "LineTestFiles/defaults2D.tga"), |
||||
/* SwiftShader has 8 different pixels on the edges */ |
||||
(DebugTools::CompareImageToFile{_manager, 238.0f, 0.2975f})); |
||||
} |
||||
|
||||
}}}} |
||||
|
||||
CORRADE_TEST_MAIN(Magnum::Shaders::Test::LineGLTest) |
||||
@ -0,0 +1,152 @@
|
||||
/*
|
||||
This file is part of Magnum. |
||||
|
||||
Copyright © 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019, |
||||
2020, 2021, 2022 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. |
||||
*/ |
||||
|
||||
#include <sstream> |
||||
#include <Corrade/Containers/String.h> |
||||
#include <Corrade/TestSuite/Tester.h> |
||||
#include <Corrade/Utility/DebugStl.h> |
||||
#include <Corrade/Utility/Format.h> |
||||
|
||||
#include "Magnum/Shaders/LineGL.h" |
||||
|
||||
namespace Magnum { namespace Shaders { namespace Test { namespace { |
||||
|
||||
/* There's an underscore between GL and Test to disambiguate from GLTest, which
|
||||
is a common suffix used to mark tests that need a GL context. Ugly, I know. */ |
||||
struct LineGL_Test: TestSuite::Tester { |
||||
explicit LineGL_Test(); |
||||
|
||||
template<UnsignedInt dimensions> void constructConfigurationDefault(); |
||||
template<UnsignedInt dimensions> void constructConfigurationSetters(); |
||||
|
||||
template<UnsignedInt dimensions> void constructNoCreate(); |
||||
template<UnsignedInt dimensions> void constructCopy(); |
||||
|
||||
void debugFlag(); |
||||
void debugFlags(); |
||||
void debugFlagsSupersets(); |
||||
}; |
||||
|
||||
LineGL_Test::LineGL_Test() { |
||||
addTests({&LineGL_Test::constructConfigurationDefault<2>, |
||||
&LineGL_Test::constructConfigurationDefault<3>, |
||||
&LineGL_Test::constructConfigurationSetters<2>, |
||||
&LineGL_Test::constructConfigurationSetters<3>, |
||||
|
||||
&LineGL_Test::constructNoCreate<2>, |
||||
&LineGL_Test::constructNoCreate<3>, |
||||
&LineGL_Test::constructCopy<2>, |
||||
&LineGL_Test::constructCopy<3>, |
||||
|
||||
&LineGL_Test::debugFlag, |
||||
&LineGL_Test::debugFlags, |
||||
&LineGL_Test::debugFlagsSupersets}); |
||||
} |
||||
|
||||
template<UnsignedInt dimensions> void LineGL_Test::constructConfigurationDefault() { |
||||
setTestCaseTemplateName(Utility::format("{}", dimensions)); |
||||
|
||||
typename LineGL<dimensions>::Configuration configuration; |
||||
CORRADE_COMPARE(configuration.flags(), typename LineGL<dimensions>::Flags{}); |
||||
#ifndef MAGNUM_TARGET_GLES2 |
||||
CORRADE_COMPARE(configuration.materialCount(), 1); |
||||
CORRADE_COMPARE(configuration.drawCount(), 1); |
||||
#endif |
||||
} |
||||
|
||||
template<UnsignedInt dimensions> void LineGL_Test::constructConfigurationSetters() { |
||||
setTestCaseTemplateName(Utility::format("{}", dimensions)); |
||||
|
||||
typename LineGL<dimensions>::Configuration configuration = typename LineGL<dimensions>::Configuration{} |
||||
.setFlags(LineGL<dimensions>::Flag::VertexColor) |
||||
#ifndef MAGNUM_TARGET_GLES2 |
||||
.setMaterialCount(17) |
||||
.setDrawCount(266) |
||||
#endif |
||||
; |
||||
CORRADE_COMPARE(configuration.flags(), LineGL<dimensions>::Flag::VertexColor); |
||||
#ifndef MAGNUM_TARGET_GLES2 |
||||
CORRADE_COMPARE(configuration.materialCount(), 17); |
||||
CORRADE_COMPARE(configuration.drawCount(), 266); |
||||
#endif |
||||
} |
||||
|
||||
template<UnsignedInt dimensions> void LineGL_Test::constructNoCreate() { |
||||
setTestCaseTemplateName(Utility::format("{}", dimensions)); |
||||
|
||||
{ |
||||
LineGL<dimensions> shader{NoCreate}; |
||||
CORRADE_COMPARE(shader.id(), 0); |
||||
CORRADE_COMPARE(shader.flags(), typename LineGL<dimensions>::Flags{}); |
||||
} |
||||
|
||||
CORRADE_VERIFY(true); |
||||
} |
||||
|
||||
template<UnsignedInt dimensions> void LineGL_Test::constructCopy() { |
||||
setTestCaseTemplateName(Utility::format("{}", dimensions)); |
||||
|
||||
CORRADE_VERIFY(!std::is_copy_constructible<LineGL<dimensions>>{}); |
||||
CORRADE_VERIFY(!std::is_copy_assignable<LineGL<dimensions>>{}); |
||||
} |
||||
|
||||
void LineGL_Test::debugFlag() { |
||||
std::ostringstream out; |
||||
|
||||
Debug{&out} << LineGL3D::Flag::VertexColor << LineGL3D::Flag(0xf00d); |
||||
CORRADE_COMPARE(out.str(), "Shaders::LineGL::Flag::VertexColor Shaders::LineGL::Flag(0xf00d)\n"); |
||||
} |
||||
|
||||
void LineGL_Test::debugFlags() { |
||||
std::ostringstream out; |
||||
|
||||
Debug{&out} << (LineGL3D::Flag::VertexColor|LineGL3D::Flag::InstancedTransformation) << LineGL3D::Flags{}; |
||||
CORRADE_COMPARE(out.str(), "Shaders::LineGL::Flag::VertexColor|Shaders::LineGL::Flag::InstancedTransformation Shaders::LineGL::Flags{}\n"); |
||||
} |
||||
|
||||
void LineGL_Test::debugFlagsSupersets() { |
||||
#ifndef MAGNUM_TARGET_GLES2 |
||||
/* InstancedObjectId is a superset of ObjectId so only one should be
|
||||
printed */ |
||||
{ |
||||
std::ostringstream out; |
||||
Debug{&out} << (LineGL3D::Flag::ObjectId|LineGL3D::Flag::InstancedObjectId); |
||||
CORRADE_COMPARE(out.str(), "Shaders::LineGL::Flag::InstancedObjectId\n"); |
||||
} |
||||
#endif |
||||
|
||||
#ifndef MAGNUM_TARGET_GLES2 |
||||
/* MultiDraw is a superset of UniformBuffers so only one should be printed */ |
||||
{ |
||||
std::ostringstream out; |
||||
Debug{&out} << (LineGL3D::Flag::MultiDraw|LineGL3D::Flag::UniformBuffers); |
||||
CORRADE_COMPARE(out.str(), "Shaders::LineGL::Flag::MultiDraw\n"); |
||||
} |
||||
#endif |
||||
} |
||||
|
||||
}}}} |
||||
|
||||
CORRADE_TEST_MAIN(Magnum::Shaders::Test::LineGL_Test) |
||||
@ -0,0 +1,196 @@
|
||||
/*
|
||||
This file is part of Magnum. |
||||
|
||||
Copyright © 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019, |
||||
2020, 2021, 2022 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. |
||||
*/ |
||||
|
||||
#include <new> |
||||
#include <Corrade/TestSuite/Tester.h> |
||||
|
||||
#include "Magnum/Shaders/Line.h" |
||||
|
||||
namespace Magnum { namespace Shaders { namespace Test { namespace { |
||||
|
||||
struct LineTest: TestSuite::Tester { |
||||
explicit LineTest(); |
||||
|
||||
template<class T> void uniformSizeAlignment(); |
||||
|
||||
void drawUniformConstructDefault(); |
||||
void drawUniformConstructNoInit(); |
||||
void drawUniformSetters(); |
||||
void drawUniformMaterialIdPacking(); |
||||
|
||||
void materialUniformConstructDefault(); |
||||
void materialUniformConstructNoInit(); |
||||
void materialUniformSetters(); |
||||
}; |
||||
|
||||
LineTest::LineTest() { |
||||
addTests({&LineTest::uniformSizeAlignment<LineDrawUniform>, |
||||
&LineTest::uniformSizeAlignment<LineMaterialUniform>, |
||||
|
||||
&LineTest::drawUniformConstructDefault, |
||||
&LineTest::drawUniformConstructNoInit, |
||||
&LineTest::drawUniformSetters, |
||||
&LineTest::drawUniformMaterialIdPacking, |
||||
|
||||
&LineTest::materialUniformConstructDefault, |
||||
&LineTest::materialUniformConstructNoInit, |
||||
&LineTest::materialUniformSetters}); |
||||
} |
||||
|
||||
using namespace Math::Literals; |
||||
|
||||
template<class> struct UniformTraits; |
||||
template<> struct UniformTraits<LineDrawUniform> { |
||||
static const char* name() { return "LineDrawUniform"; } |
||||
}; |
||||
template<> struct UniformTraits<LineMaterialUniform> { |
||||
static const char* name() { return "LineMaterialUniform"; } |
||||
}; |
||||
|
||||
template<class T> void LineTest::uniformSizeAlignment() { |
||||
setTestCaseTemplateName(UniformTraits<T>::name()); |
||||
|
||||
CORRADE_FAIL_IF(sizeof(T) % sizeof(Vector4) != 0, sizeof(T) << "is not a multiple of vec4 for UBO alignment."); |
||||
|
||||
/* 48-byte structures are fine, we'll align them to 768 bytes and not
|
||||
256, but warn about that */ |
||||
CORRADE_FAIL_IF(768 % sizeof(T) != 0, sizeof(T) << "can't fit exactly into 768-byte UBO alignment."); |
||||
if(256 % sizeof(T) != 0) |
||||
CORRADE_WARN(sizeof(T) << "can't fit exactly into 256-byte UBO alignment, only 768."); |
||||
|
||||
CORRADE_COMPARE(alignof(T), 4); |
||||
} |
||||
|
||||
void LineTest::drawUniformConstructDefault() { |
||||
LineDrawUniform a; |
||||
LineDrawUniform b{DefaultInit}; |
||||
CORRADE_COMPARE(a.materialId, 0); |
||||
CORRADE_COMPARE(b.materialId, 0); |
||||
CORRADE_COMPARE(a.objectId, 0); |
||||
CORRADE_COMPARE(b.objectId, 0); |
||||
|
||||
constexpr LineDrawUniform ca; |
||||
constexpr LineDrawUniform cb{DefaultInit}; |
||||
CORRADE_COMPARE(ca.materialId, 0); |
||||
CORRADE_COMPARE(cb.materialId, 0); |
||||
CORRADE_COMPARE(ca.objectId, 0); |
||||
CORRADE_COMPARE(cb.objectId, 0); |
||||
|
||||
CORRADE_VERIFY(std::is_nothrow_default_constructible<LineDrawUniform>::value); |
||||
CORRADE_VERIFY(std::is_nothrow_constructible<LineDrawUniform, DefaultInitT>::value); |
||||
|
||||
/* Implicit construction is not allowed */ |
||||
CORRADE_VERIFY(!std::is_convertible<DefaultInitT, LineDrawUniform>::value); |
||||
} |
||||
|
||||
void LineTest::drawUniformConstructNoInit() { |
||||
/* Testing only some fields, should be enough */ |
||||
LineDrawUniform a; |
||||
a.materialId = 5; |
||||
a.objectId = 7; |
||||
|
||||
new(&a) LineDrawUniform{NoInit}; |
||||
{ |
||||
/* Explicitly check we're not on Clang because certain Clang-based IDEs
|
||||
inherit __GNUC__ if GCC is used instead of leaving it at 4 like |
||||
Clang itself does */ |
||||
#if defined(CORRADE_TARGET_GCC) && !defined(CORRADE_TARGET_CLANG) && __GNUC__*100 + __GNUC_MINOR__ >= 601 && __OPTIMIZE__ |
||||
CORRADE_EXPECT_FAIL("GCC 6.1+ misoptimizes and overwrites the value."); |
||||
#endif |
||||
CORRADE_COMPARE(a.materialId, 5); |
||||
CORRADE_COMPARE(a.objectId, 7); |
||||
} |
||||
|
||||
CORRADE_VERIFY(std::is_nothrow_constructible<LineDrawUniform, NoInitT>::value); |
||||
|
||||
/* Implicit construction is not allowed */ |
||||
CORRADE_VERIFY(!std::is_convertible<NoInitT, LineDrawUniform>::value); |
||||
} |
||||
|
||||
void LineTest::drawUniformSetters() { |
||||
LineDrawUniform a; |
||||
a.setMaterialId(5) |
||||
.setObjectId(7); |
||||
CORRADE_COMPARE(a.materialId, 5); |
||||
CORRADE_COMPARE(a.objectId, 7); |
||||
} |
||||
|
||||
void LineTest::drawUniformMaterialIdPacking() { |
||||
LineDrawUniform a; |
||||
a.setMaterialId(13765); |
||||
/* materialId should be right at the beginning, in the low 16 bits on both
|
||||
LE and BE */ |
||||
CORRADE_COMPARE(reinterpret_cast<UnsignedInt*>(&a)[0] & 0xffff, 13765); |
||||
} |
||||
|
||||
void LineTest::materialUniformConstructDefault() { |
||||
LineMaterialUniform a; |
||||
LineMaterialUniform b{DefaultInit}; |
||||
CORRADE_COMPARE(a.color, 0xffffffff_rgbaf); |
||||
CORRADE_COMPARE(b.color, 0xffffffff_rgbaf); |
||||
|
||||
constexpr LineMaterialUniform ca; |
||||
constexpr LineMaterialUniform cb{DefaultInit}; |
||||
CORRADE_COMPARE(ca.color, 0xffffffff_rgbaf); |
||||
CORRADE_COMPARE(cb.color, 0xffffffff_rgbaf); |
||||
|
||||
CORRADE_VERIFY(std::is_nothrow_default_constructible<LineDrawUniform>::value); |
||||
CORRADE_VERIFY(std::is_nothrow_constructible<LineDrawUniform, DefaultInitT>::value); |
||||
|
||||
/* Implicit construction is not allowed */ |
||||
CORRADE_VERIFY(!std::is_convertible<DefaultInitT, LineDrawUniform>::value); |
||||
} |
||||
|
||||
void LineTest::materialUniformConstructNoInit() { |
||||
/* Testing only some fields, should be enough */ |
||||
LineMaterialUniform a; |
||||
a.color = 0x354565fc_rgbaf; |
||||
|
||||
new(&a) LineMaterialUniform{NoInit}; |
||||
{ |
||||
/* Explicitly check we're not on Clang because certain Clang-based IDEs
|
||||
inherit __GNUC__ if GCC is used instead of leaving it at 4 like |
||||
Clang itself does */ |
||||
#if defined(CORRADE_TARGET_GCC) && !defined(CORRADE_TARGET_CLANG) && __GNUC__*100 + __GNUC_MINOR__ >= 601 && __OPTIMIZE__ |
||||
CORRADE_EXPECT_FAIL("GCC 6.1+ misoptimizes and overwrites the value."); |
||||
#endif |
||||
CORRADE_COMPARE(a.color, 0x354565fc_rgbaf); |
||||
} |
||||
|
||||
CORRADE_VERIFY(std::is_nothrow_constructible<LineMaterialUniform, NoInitT>::value); |
||||
|
||||
/* Implicit construction is not allowed */ |
||||
CORRADE_VERIFY(!std::is_convertible<NoInitT, LineMaterialUniform>::value); |
||||
} |
||||
|
||||
void LineTest::materialUniformSetters() { |
||||
LineMaterialUniform a; |
||||
a.setColor(0x354565fc_rgbaf); |
||||
CORRADE_COMPARE(a.color, 0x354565fc_rgbaf); |
||||
} |
||||
|
||||
}}}} |
||||
|
||||
CORRADE_TEST_MAIN(Magnum::Shaders::Test::LineTest) |
||||
Loading…
Reference in new issue