diff --git a/src/Magnum/Shaders/MeshVisualizer.cpp b/src/Magnum/Shaders/MeshVisualizer.cpp index 71a50fd86..08d2e6e43 100644 --- a/src/Magnum/Shaders/MeshVisualizer.cpp +++ b/src/Magnum/Shaders/MeshVisualizer.cpp @@ -37,12 +37,16 @@ namespace Magnum { namespace Shaders { MeshVisualizer::MeshVisualizer(const Flags flags): flags(flags), transformationProjectionMatrixUniform(0), viewportSizeUniform(1), colorUniform(2), wireframeColorUniform(3), wireframeWidthUniform(4), smoothnessUniform(5) { - #ifndef MAGNUM_TARGET_GLES + #ifndef MAGNUM_TARGET_GLES2 if(flags & Flag::Wireframe && !(flags & Flag::NoGeometryShader)) { + #ifndef MAGNUM_TARGET_GLES MAGNUM_ASSERT_VERSION_SUPPORTED(Version::GL320); MAGNUM_ASSERT_EXTENSION_SUPPORTED(Extensions::GL::ARB::geometry_shader4); + #else + MAGNUM_ASSERT_EXTENSION_SUPPORTED(Extensions::GL::EXT::geometry_shader); + #endif } - #elif defined(MAGNUM_TARGET_GLES2) + #else if(flags & Flag::Wireframe) MAGNUM_ASSERT_EXTENSION_SUPPORTED(Extensions::GL::OES::standard_derivatives); #endif @@ -58,7 +62,8 @@ MeshVisualizer::MeshVisualizer(const Flags flags): flags(flags), transformationP const Version version = Context::current()->supportedVersion({Version::GL320, Version::GL310, Version::GL300, Version::GL210}); CORRADE_INTERNAL_ASSERT(flags & Flag::NoGeometryShader || version >= Version::GL320); #else - const Version version = Context::current()->supportedVersion({Version::GLES300, Version::GLES200}); + const Version version = Context::current()->supportedVersion({Version::GLES310, Version::GLES300, Version::GLES200}); + CORRADE_INTERNAL_ASSERT(flags & Flag::NoGeometryShader || version >= Version::GLES310); #endif Shader vert = Implementation::createCompatibilityShader(rs, version, Shader::Type::Vertex); @@ -78,7 +83,7 @@ MeshVisualizer::MeshVisualizer(const Flags flags): flags(flags), transformationP .addSource(flags & Flag::NoGeometryShader ? "#define NO_GEOMETRY_SHADER\n" : "") .addSource(rs.get("MeshVisualizer.frag")); - #ifndef MAGNUM_TARGET_GLES + #ifndef MAGNUM_TARGET_GLES2 std::optional geom; if(flags & Flag::Wireframe && !(flags & Flag::NoGeometryShader)) { geom = Implementation::createCompatibilityShader(rs, version, Shader::Type::Geometry); @@ -86,14 +91,14 @@ MeshVisualizer::MeshVisualizer(const Flags flags): flags(flags), transformationP } #endif - #ifndef MAGNUM_TARGET_GLES + #ifndef MAGNUM_TARGET_GLES2 if(geom) CORRADE_INTERNAL_ASSERT_OUTPUT(Shader::compile({vert, *geom, frag})); else #endif CORRADE_INTERNAL_ASSERT_OUTPUT(Shader::compile({vert, frag})); attachShaders({vert, frag}); - #ifndef MAGNUM_TARGET_GLES + #ifndef MAGNUM_TARGET_GLES2 if(geom) attachShader(*geom); #endif diff --git a/src/Magnum/Shaders/MeshVisualizer.frag b/src/Magnum/Shaders/MeshVisualizer.frag index ce613fb14..8c48eb079 100644 --- a/src/Magnum/Shaders/MeshVisualizer.frag +++ b/src/Magnum/Shaders/MeshVisualizer.frag @@ -40,6 +40,10 @@ #extension GL_OES_standard_derivatives : enable #endif +#if defined(GL_ES) && !defined(NO_GEOMETRY_SHADER) && defined(GL_NV_shader_noperspective_interpolation) +#extension GL_NV_shader_noperspective_interpolation: require +#endif + #ifndef GL_ES layout(location = 2) uniform vec4 color = vec4(1.0, 1.0, 1.0, 1.0); #else @@ -58,7 +62,10 @@ uniform lowp float smoothness; #endif #ifndef NO_GEOMETRY_SHADER -noperspective in lowp vec3 dist; +#ifdef GL_NV_shader_noperspective_interpolation +noperspective +#endif +in lowp vec3 dist; #else in lowp vec3 barycentric; #endif @@ -72,7 +79,7 @@ void main() { #ifdef WIREFRAME_RENDERING #ifndef NO_GEOMETRY_SHADER /* Distance to nearest side */ - const float nearest = min(min(dist.x, dist.y), dist.z); + lowp const float nearest = min(min(dist.x, dist.y), dist.z); /* Smooth step between face color and wireframe color based on distance */ fragmentColor = mix(wireframeColor, color, smoothstep(wireframeWidth-smoothness, wireframeWidth+smoothness, nearest)); diff --git a/src/Magnum/Shaders/MeshVisualizer.geom b/src/Magnum/Shaders/MeshVisualizer.geom index e2825989e..109e21fe2 100644 --- a/src/Magnum/Shaders/MeshVisualizer.geom +++ b/src/Magnum/Shaders/MeshVisualizer.geom @@ -27,6 +27,13 @@ #define const #endif +#ifdef GL_ES +#extension GL_EXT_geometry_shader: require +#ifdef GL_NV_shader_noperspective_interpolation +#extension GL_NV_shader_noperspective_interpolation: require +#endif +#endif + #ifdef EXPLICIT_UNIFORM_LOCATION layout(location = 1) uniform vec2 viewportSize; #else @@ -37,8 +44,11 @@ layout(triangles) in; layout(triangle_strip, max_vertices = 3) out; -/* Interpolate in screen space */ -noperspective out vec3 dist; +/* Interpolate in screen space (if possible) */ +#ifdef GL_NV_shader_noperspective_interpolation +noperspective +#endif +out lowp vec3 dist; void main() { /* Screen position of each vertex */ @@ -47,11 +57,11 @@ void main() { p[i] = viewportSize*gl_in[i].gl_Position.xy/gl_in[i].gl_Position.w; /* Vector of each triangle side */ - const vec2 v[3] = { + const vec2 v[3] = vec2[3]( p[2]-p[1], p[2]-p[0], p[1]-p[0] - }; + ); /* Compute area using perp-dot product */ const float area = abs(dot(vec2(-v[1].y, v[1].x), v[2])); diff --git a/src/Magnum/Shaders/MeshVisualizer.h b/src/Magnum/Shaders/MeshVisualizer.h index 3d5a61083..44b235edb 100644 --- a/src/Magnum/Shaders/MeshVisualizer.h +++ b/src/Magnum/Shaders/MeshVisualizer.h @@ -56,15 +56,20 @@ If you have geometry shaders available, you don't need to do anything else. @requires_gl32 Extension @extension{ARB,geometry_shader4} for wireframe rendering using geometry shaders. +@requires_es_extension Extension @es_extension{EXT,geometry_shader} for + wireframe rendering using geometry shaders. If you don't have geometry shaders, you need to set @ref Flag::NoGeometryShader -(it's enabled by default in OpenGL ES) and use only **non-indexed** triangle +(it's enabled by default in OpenGL ES 2.0) and use only **non-indexed** triangle meshes (see @ref MeshTools::duplicate() for possible solution). Additionaly, if you have OpenGL < 3.1 or OpenGL ES 2.0, you need to provide also @ref VertexIndex attribute. -@requires_es_extension Extension @extension{OES,standard_derivatives} for - wireframe rendering. +@requires_gles30 Extension @es_extension{OES,standard_derivatives} for + wireframe rendering without geometry shaders. + +If using geometry shaders on OpenGL ES, @es_extension{NV,shader_noperspective_interpolation} +is optionally used for improving line appearance. ## Example usage @@ -174,10 +179,10 @@ class MAGNUM_SHADERS_EXPORT MeshVisualizer: public AbstractShaderProgram { */ enum class Flag: UnsignedByte { /** - * Visualize wireframe. On OpenGL ES this also enables + * Visualize wireframe. On OpenGL ES 2.0 this also enables * @ref Flag::NoGeometryShader. */ - #ifndef MAGNUM_TARGET_GLES + #ifndef MAGNUM_TARGET_GLES2 Wireframe = 1 << 0, #else Wireframe = (1 << 0) | (1 << 1), diff --git a/src/Magnum/Shaders/Test/MeshVisualizerGLTest.cpp b/src/Magnum/Shaders/Test/MeshVisualizerGLTest.cpp index 0f3141f5b..47a029199 100644 --- a/src/Magnum/Shaders/Test/MeshVisualizerGLTest.cpp +++ b/src/Magnum/Shaders/Test/MeshVisualizerGLTest.cpp @@ -34,13 +34,17 @@ struct MeshVisualizerGLTest: Magnum::Test::AbstractOpenGLTester { explicit MeshVisualizerGLTest(); void compile(); + #if !defined(MAGNUM_TARGET_GLES2) && !defined(MAGNUM_TARGET_WEBGL) void compileWireframeGeometryShader(); + #endif void compileWireframeNoGeometryShader(); }; MeshVisualizerGLTest::MeshVisualizerGLTest() { addTests({&MeshVisualizerGLTest::compile, + #if !defined(MAGNUM_TARGET_GLES2) && !defined(MAGNUM_TARGET_WEBGL) &MeshVisualizerGLTest::compileWireframeGeometryShader, + #endif &MeshVisualizerGLTest::compileWireframeNoGeometryShader}); } @@ -49,17 +53,23 @@ void MeshVisualizerGLTest::compile() { CORRADE_VERIFY(shader.validate().first); } +#if !defined(MAGNUM_TARGET_GLES2) && !defined(MAGNUM_TARGET_WEBGL) void MeshVisualizerGLTest::compileWireframeGeometryShader() { - #ifdef MAGNUM_TARGET_GLES - CORRADE_SKIP("Geometry shader is not available in OpenGL ES"); - #else + #ifndef MAGNUM_TARGET_GLES if(!Context::current()->isExtensionSupported()) CORRADE_SKIP(Extensions::GL::ARB::geometry_shader4::string() + std::string(" is not supported")); + #else + if(!Context::current()->isExtensionSupported()) + CORRADE_SKIP(Extensions::GL::EXT::geometry_shader::string() + std::string(" is not supported")); + #endif + + if(Context::current()->isExtensionSupported()) + Debug() << "Using" << Extensions::GL::NV::shader_noperspective_interpolation::string(); Shaders::MeshVisualizer shader(Shaders::MeshVisualizer::Flag::Wireframe); CORRADE_VERIFY(shader.validate().first); - #endif } +#endif void MeshVisualizerGLTest::compileWireframeNoGeometryShader() { Shaders::MeshVisualizer shader(Shaders::MeshVisualizer::Flag::Wireframe|Shaders::MeshVisualizer::Flag::NoGeometryShader);