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