From 707c8c1e95d8db2d84909e7957b4dc9138e05599 Mon Sep 17 00:00:00 2001 From: Vitaliy Date: Sun, 25 Oct 2020 20:01:03 +0300 Subject: [PATCH] Shaders for Android (GLES 2) (#10506) Shader support for OpenGL ES 2 devices (Android) Co-authored-by: sfan5 --- build/android/app/build.gradle | 5 +- builtin/mainmenu/tab_settings.lua | 11 +- builtin/settingtypes.txt | 4 +- .../3d_interlaced_merge/opengl_fragment.glsl | 4 +- .../3d_interlaced_merge/opengl_vertex.glsl | 7 +- .../default_shader/opengl_fragment.glsl | 4 +- .../shaders/default_shader/opengl_vertex.glsl | 8 +- .../minimap_shader/opengl_fragment.glsl | 7 +- .../shaders/minimap_shader/opengl_vertex.glsl | 10 +- .../shaders/nodes_shader/opengl_fragment.glsl | 13 +- .../shaders/nodes_shader/opengl_vertex.glsl | 42 ++-- .../object_shader/opengl_fragment.glsl | 11 +- .../shaders/object_shader/opengl_vertex.glsl | 25 +-- .../selection_shader/opengl_fragment.glsl | 7 +- .../selection_shader/opengl_vertex.glsl | 9 +- games/devtest/mods/basenodes/init.lua | 4 + src/client/shader.cpp | 182 +++++++++++++----- 17 files changed, 233 insertions(+), 120 deletions(-) diff --git a/build/android/app/build.gradle b/build/android/app/build.gradle index 812726030..fccb7b3b4 100644 --- a/build/android/app/build.gradle +++ b/build/android/app/build.gradle @@ -64,10 +64,9 @@ task prepareAssets() { copy { from "${projRoot}/builtin" into "${assetsFolder}/builtin" } - /*copy { - // ToDo: fix Minetest shaders that currently don't work with OpenGL ES + copy { from "${projRoot}/client/shaders" into "${assetsFolder}/client/shaders" - }*/ + } copy { from "../native/deps/Android/Irrlicht/shaders" into "${assetsFolder}/client/shaders/Irrlicht" } diff --git a/builtin/mainmenu/tab_settings.lua b/builtin/mainmenu/tab_settings.lua index 8a7445394..29744048a 100644 --- a/builtin/mainmenu/tab_settings.lua +++ b/builtin/mainmenu/tab_settings.lua @@ -154,15 +154,18 @@ local function formspec(tabview, name, tabdata) "box[8,0;3.75,4.5;#999999]" local video_driver = core.settings:get("video_driver") - local shaders_supported = video_driver == "opengl" - local shaders_enabled = false - if shaders_supported then - shaders_enabled = core.settings:get_bool("enable_shaders") + local shaders_enabled = core.settings:get_bool("enable_shaders") + if video_driver == "opengl" then tab_string = tab_string .. "checkbox[8.25,0;cb_shaders;" .. fgettext("Shaders") .. ";" .. tostring(shaders_enabled) .. "]" + elseif video_driver == "ogles2" then + tab_string = tab_string .. + "checkbox[8.25,0;cb_shaders;" .. fgettext("Shaders (experimental)") .. ";" + .. tostring(shaders_enabled) .. "]" else core.settings:set_bool("enable_shaders", false) + shaders_enabled = false tab_string = tab_string .. "label[8.38,0.2;" .. core.colorize("#888888", fgettext("Shaders (unavailable)")) .. "]" diff --git a/builtin/settingtypes.txt b/builtin/settingtypes.txt index 27f375693..36446f808 100644 --- a/builtin/settingtypes.txt +++ b/builtin/settingtypes.txt @@ -658,8 +658,8 @@ texture_path (Texture path) path # The rendering back-end for Irrlicht. # A restart is required after changing this. # Note: On Android, stick with OGLES1 if unsure! App may fail to start otherwise. -# On other platforms, OpenGL is recommended, and it’s the only driver with -# shader support currently. +# On other platforms, OpenGL is recommended. +# Shaders are supported by OpenGL (desktop only) and OGLES2 (experimental) video_driver (Video driver) enum opengl null,software,burningsvideo,direct3d8,direct3d9,opengl,ogles1,ogles2 # Radius of cloud area stated in number of 64 node cloud squares. diff --git a/client/shaders/3d_interlaced_merge/opengl_fragment.glsl b/client/shaders/3d_interlaced_merge/opengl_fragment.glsl index 25945ad7f..7cba61b39 100644 --- a/client/shaders/3d_interlaced_merge/opengl_fragment.glsl +++ b/client/shaders/3d_interlaced_merge/opengl_fragment.glsl @@ -6,9 +6,11 @@ uniform sampler2D textureFlags; #define rightImage normalTexture #define maskImage textureFlags +varying mediump vec2 varTexCoord; + void main(void) { - vec2 uv = gl_TexCoord[0].st; + vec2 uv = varTexCoord.st; vec4 left = texture2D(leftImage, uv).rgba; vec4 right = texture2D(rightImage, uv).rgba; vec4 mask = texture2D(maskImage, uv).rgba; diff --git a/client/shaders/3d_interlaced_merge/opengl_vertex.glsl b/client/shaders/3d_interlaced_merge/opengl_vertex.glsl index 4e0b2b125..860049481 100644 --- a/client/shaders/3d_interlaced_merge/opengl_vertex.glsl +++ b/client/shaders/3d_interlaced_merge/opengl_vertex.glsl @@ -1,6 +1,7 @@ +varying mediump vec2 varTexCoord; + void main(void) { - gl_TexCoord[0] = gl_MultiTexCoord0; - gl_Position = gl_Vertex; - gl_FrontColor = gl_BackColor = gl_Color; + varTexCoord = inTexCoord0; + gl_Position = inVertexPosition; } diff --git a/client/shaders/default_shader/opengl_fragment.glsl b/client/shaders/default_shader/opengl_fragment.glsl index 925ab6e1d..5018ac6ea 100644 --- a/client/shaders/default_shader/opengl_fragment.glsl +++ b/client/shaders/default_shader/opengl_fragment.glsl @@ -1,4 +1,6 @@ +varying lowp vec4 varColor; + void main(void) { - gl_FragColor = gl_Color; + gl_FragColor = varColor; } diff --git a/client/shaders/default_shader/opengl_vertex.glsl b/client/shaders/default_shader/opengl_vertex.glsl index d0b16c8b0..d95a3c2d3 100644 --- a/client/shaders/default_shader/opengl_vertex.glsl +++ b/client/shaders/default_shader/opengl_vertex.glsl @@ -1,9 +1,7 @@ -uniform mat4 mWorldViewProj; +varying lowp vec4 varColor; void main(void) { - gl_TexCoord[0] = gl_MultiTexCoord0; - gl_Position = mWorldViewProj * gl_Vertex; - - gl_FrontColor = gl_BackColor = gl_Color; + gl_Position = mWorldViewProj * inVertexPosition; + varColor = inVertexColor; } diff --git a/client/shaders/minimap_shader/opengl_fragment.glsl b/client/shaders/minimap_shader/opengl_fragment.glsl index fa4f9cb1a..cef359e8a 100644 --- a/client/shaders/minimap_shader/opengl_fragment.glsl +++ b/client/shaders/minimap_shader/opengl_fragment.glsl @@ -2,9 +2,12 @@ uniform sampler2D baseTexture; uniform sampler2D normalTexture; uniform vec3 yawVec; +varying lowp vec4 varColor; +varying mediump vec2 varTexCoord; + void main (void) { - vec2 uv = gl_TexCoord[0].st; + vec2 uv = varTexCoord.st; //texture sampling rate const float step = 1.0 / 256.0; @@ -27,6 +30,6 @@ void main (void) vec3 color = (1.1 * diffuse + 0.05 * height + 0.5 * specular) * base.rgb; vec4 col = vec4(color.rgb, base.a); - col *= gl_Color; + col *= varColor; gl_FragColor = vec4(col.rgb, base.a); } diff --git a/client/shaders/minimap_shader/opengl_vertex.glsl b/client/shaders/minimap_shader/opengl_vertex.glsl index 88f9356d5..1a9491805 100644 --- a/client/shaders/minimap_shader/opengl_vertex.glsl +++ b/client/shaders/minimap_shader/opengl_vertex.glsl @@ -1,9 +1,11 @@ -uniform mat4 mWorldViewProj; uniform mat4 mWorld; +varying lowp vec4 varColor; +varying mediump vec2 varTexCoord; + void main(void) { - gl_TexCoord[0] = gl_MultiTexCoord0; - gl_Position = mWorldViewProj * gl_Vertex; - gl_FrontColor = gl_BackColor = gl_Color; + varTexCoord = inTexCoord0.st; + gl_Position = mWorldViewProj * inVertexPosition; + varColor = inVertexColor; } diff --git a/client/shaders/nodes_shader/opengl_fragment.glsl b/client/shaders/nodes_shader/opengl_fragment.glsl index 36d47d1f5..82c87073a 100644 --- a/client/shaders/nodes_shader/opengl_fragment.glsl +++ b/client/shaders/nodes_shader/opengl_fragment.glsl @@ -15,11 +15,12 @@ varying vec3 vPosition; // cameraOffset + worldPosition (for large coordinates the limits of float // precision must be considered). varying vec3 worldPosition; - +varying lowp vec4 varColor; +varying mediump vec2 varTexCoord; varying vec3 eyeVec; const float fogStart = FOG_START; -const float fogShadingParameter = 1 / ( 1 - fogStart); +const float fogShadingParameter = 1.0 / ( 1.0 - fogStart); #ifdef ENABLE_TONE_MAPPING @@ -56,13 +57,13 @@ vec4 applyToneMapping(vec4 color) void main(void) { vec3 color; - vec2 uv = gl_TexCoord[0].st; + vec2 uv = varTexCoord.st; vec4 base = texture2D(baseTexture, uv).rgba; - #ifdef USE_DISCARD // If alpha is zero, we can just discard the pixel. This fixes transparency - // on GPUs like GC7000L, where GL_ALPHA_TEST is not implemented in mesa. + // on GPUs like GC7000L, where GL_ALPHA_TEST is not implemented in mesa, + // and also on GLES 2, where GL_ALPHA_TEST is missing entirely. if (base.a == 0.0) { discard; } @@ -70,7 +71,7 @@ void main(void) color = base.rgb; - vec4 col = vec4(color.rgb * gl_Color.rgb, 1.0); + vec4 col = vec4(color.rgb * varColor.rgb, 1.0); #ifdef ENABLE_TONE_MAPPING col = applyToneMapping(col); diff --git a/client/shaders/nodes_shader/opengl_vertex.glsl b/client/shaders/nodes_shader/opengl_vertex.glsl index 56bff09a8..cb344f6e6 100644 --- a/client/shaders/nodes_shader/opengl_vertex.glsl +++ b/client/shaders/nodes_shader/opengl_vertex.glsl @@ -1,4 +1,3 @@ -uniform mat4 mWorldViewProj; uniform mat4 mWorld; // Color of the light emitted by the sun. @@ -16,7 +15,8 @@ varying vec3 vPosition; // cameraOffset + worldPosition (for large coordinates the limits of float // precision must be considered). varying vec3 worldPosition; - +varying lowp vec4 varColor; +varying mediump vec2 varTexCoord; varying vec3 eyeVec; // Color of the light emitted by the light sources. @@ -81,13 +81,13 @@ float snoise(vec3 p) void main(void) { - gl_TexCoord[0] = gl_MultiTexCoord0; + varTexCoord = inTexCoord0.st; float disp_x; float disp_z; // OpenGL < 4.3 does not support continued preprocessor lines #if (MATERIAL_TYPE == TILE_MATERIAL_WAVING_LEAVES && ENABLE_WAVING_LEAVES) || (MATERIAL_TYPE == TILE_MATERIAL_WAVING_PLANTS && ENABLE_WAVING_PLANTS) - vec4 pos2 = mWorld * gl_Vertex; + vec4 pos2 = mWorld * inVertexPosition; float tOffset = (pos2.x + pos2.y) * 0.001 + pos2.z * 0.002; disp_x = (smoothTriangleWave(animationTimer * 23.0 + tOffset) + smoothTriangleWave(animationTimer * 11.0 + tOffset)) * 0.4; @@ -96,43 +96,43 @@ void main(void) smoothTriangleWave(animationTimer * 13.0 + tOffset)) * 0.5; #endif - worldPosition = (mWorld * gl_Vertex).xyz; + worldPosition = (mWorld * inVertexPosition).xyz; // OpenGL < 4.3 does not support continued preprocessor lines #if (MATERIAL_TYPE == TILE_MATERIAL_WAVING_LIQUID_TRANSPARENT || MATERIAL_TYPE == TILE_MATERIAL_WAVING_LIQUID_OPAQUE || MATERIAL_TYPE == TILE_MATERIAL_WAVING_LIQUID_BASIC) && ENABLE_WAVING_WATER // Generate waves with Perlin-type noise. // The constants are calibrated such that they roughly // correspond to the old sine waves. - vec4 pos = gl_Vertex; + vec4 pos = inVertexPosition; vec3 wavePos = worldPosition + cameraOffset; // The waves are slightly compressed along the z-axis to get // wave-fronts along the x-axis. - wavePos.x /= WATER_WAVE_LENGTH * 3; - wavePos.z /= WATER_WAVE_LENGTH * 2; - wavePos.z += animationTimer * WATER_WAVE_SPEED * 10; - pos.y += (snoise(wavePos) - 1) * WATER_WAVE_HEIGHT * 5; + wavePos.x /= WATER_WAVE_LENGTH * 3.0; + wavePos.z /= WATER_WAVE_LENGTH * 2.0; + wavePos.z += animationTimer * WATER_WAVE_SPEED * 10.0; + pos.y += (snoise(wavePos) - 1.0) * WATER_WAVE_HEIGHT * 5.0; gl_Position = mWorldViewProj * pos; #elif MATERIAL_TYPE == TILE_MATERIAL_WAVING_LEAVES && ENABLE_WAVING_LEAVES - vec4 pos = gl_Vertex; + vec4 pos = inVertexPosition; pos.x += disp_x; pos.y += disp_z * 0.1; pos.z += disp_z; gl_Position = mWorldViewProj * pos; #elif MATERIAL_TYPE == TILE_MATERIAL_WAVING_PLANTS && ENABLE_WAVING_PLANTS - vec4 pos = gl_Vertex; - if (gl_TexCoord[0].y < 0.05) { + vec4 pos = inVertexPosition; + if (varTexCoord.y < 0.05) { pos.x += disp_x; pos.z += disp_z; } gl_Position = mWorldViewProj * pos; #else - gl_Position = mWorldViewProj * gl_Vertex; + gl_Position = mWorldViewProj * inVertexPosition; #endif vPosition = gl_Position.xyz; - eyeVec = -(gl_ModelViewMatrix * gl_Vertex).xyz; + eyeVec = -(mWorldView * inVertexPosition).xyz; // Calculate color. // Red, green and blue components are pre-multiplied with @@ -141,16 +141,16 @@ void main(void) // The pre-baked colors are halved to prevent overflow. vec4 color; // The alpha gives the ratio of sunlight in the incoming light. - float nightRatio = 1 - gl_Color.a; - color.rgb = gl_Color.rgb * (gl_Color.a * dayLight.rgb + - nightRatio * artificialLight.rgb) * 2; - color.a = 1; + float nightRatio = 1.0 - inVertexColor.a; + color.rgb = inVertexColor.rgb * (inVertexColor.a * dayLight.rgb + + nightRatio * artificialLight.rgb) * 2.0; + color.a = 1.0; // Emphase blue a bit in darker places // See C++ implementation in mapblock_mesh.cpp final_color_blend() - float brightness = (color.r + color.g + color.b) / 3; + float brightness = (color.r + color.g + color.b) / 3.0; color.b += max(0.0, 0.021 - abs(0.2 * brightness - 0.021) + 0.07 * brightness); - gl_FrontColor = gl_BackColor = clamp(color, 0.0, 1.0); + varColor = clamp(color, 0.0, 1.0); } diff --git a/client/shaders/object_shader/opengl_fragment.glsl b/client/shaders/object_shader/opengl_fragment.glsl index 86d5c1c92..7ac182a63 100644 --- a/client/shaders/object_shader/opengl_fragment.glsl +++ b/client/shaders/object_shader/opengl_fragment.glsl @@ -8,6 +8,8 @@ uniform vec3 eyePosition; varying vec3 vNormal; varying vec3 vPosition; varying vec3 worldPosition; +varying lowp vec4 varColor; +varying mediump vec2 varTexCoord; varying vec3 eyeVec; varying float vIDiff; @@ -15,7 +17,7 @@ varying float vIDiff; const float e = 2.718281828459; const float BS = 10.0; const float fogStart = FOG_START; -const float fogShadingParameter = 1 / ( 1 - fogStart); +const float fogShadingParameter = 1.0 / (1.0 - fogStart); #ifdef ENABLE_TONE_MAPPING @@ -52,13 +54,14 @@ vec4 applyToneMapping(vec4 color) void main(void) { vec3 color; - vec2 uv = gl_TexCoord[0].st; + vec2 uv = varTexCoord.st; vec4 base = texture2D(baseTexture, uv).rgba; #ifdef USE_DISCARD // If alpha is zero, we can just discard the pixel. This fixes transparency - // on GPUs like GC7000L, where GL_ALPHA_TEST is not implemented in mesa. + // on GPUs like GC7000L, where GL_ALPHA_TEST is not implemented in mesa, + // and also on GLES 2, where GL_ALPHA_TEST is missing entirely. if (base.a == 0.0) { discard; } @@ -68,7 +71,7 @@ void main(void) vec4 col = vec4(color.rgb, base.a); - col.rgb *= gl_Color.rgb; + col.rgb *= varColor.rgb; col.rgb *= emissiveColor.rgb * vIDiff; diff --git a/client/shaders/object_shader/opengl_vertex.glsl b/client/shaders/object_shader/opengl_vertex.glsl index f8c1cd932..e44984dc8 100644 --- a/client/shaders/object_shader/opengl_vertex.glsl +++ b/client/shaders/object_shader/opengl_vertex.glsl @@ -1,4 +1,3 @@ -uniform mat4 mWorldViewProj; uniform mat4 mWorld; uniform vec3 eyePosition; @@ -7,6 +6,8 @@ uniform float animationTimer; varying vec3 vNormal; varying vec3 vPosition; varying vec3 worldPosition; +varying lowp vec4 varColor; +varying mediump vec2 varTexCoord; varying vec3 eyeVec; varying float vIDiff; @@ -18,31 +19,31 @@ float directional_ambient(vec3 normal) { vec3 v = normal * normal; - if (normal.y < 0) - return dot(v, vec3(0.670820f, 0.447213f, 0.836660f)); + if (normal.y < 0.0) + return dot(v, vec3(0.670820, 0.447213, 0.836660)); - return dot(v, vec3(0.670820f, 1.000000f, 0.836660f)); + return dot(v, vec3(0.670820, 1.000000, 0.836660)); } void main(void) { - gl_TexCoord[0] = gl_TextureMatrix[0] * gl_MultiTexCoord0; - gl_Position = mWorldViewProj * gl_Vertex; + varTexCoord = (mTexture * inTexCoord0).st; + gl_Position = mWorldViewProj * inVertexPosition; vPosition = gl_Position.xyz; - vNormal = gl_Normal; - worldPosition = (mWorld * gl_Vertex).xyz; - eyeVec = -(gl_ModelViewMatrix * gl_Vertex).xyz; + vNormal = inVertexNormal; + worldPosition = (mWorld * inVertexPosition).xyz; + eyeVec = -(mWorldView * inVertexPosition).xyz; #if (MATERIAL_TYPE == TILE_MATERIAL_PLAIN) || (MATERIAL_TYPE == TILE_MATERIAL_PLAIN_ALPHA) vIDiff = 1.0; #else // This is intentional comparison with zero without any margin. // If normal is not equal to zero exactly, then we assume it's a valid, just not normalized vector - vIDiff = length(gl_Normal) == 0.0 + vIDiff = length(inVertexNormal) == 0.0 ? 1.0 - : directional_ambient(normalize(gl_Normal)); + : directional_ambient(normalize(inVertexNormal)); #endif - gl_FrontColor = gl_BackColor = gl_Color; + varColor = inVertexColor; } diff --git a/client/shaders/selection_shader/opengl_fragment.glsl b/client/shaders/selection_shader/opengl_fragment.glsl index c679d0e12..35b1f8902 100644 --- a/client/shaders/selection_shader/opengl_fragment.glsl +++ b/client/shaders/selection_shader/opengl_fragment.glsl @@ -1,9 +1,12 @@ uniform sampler2D baseTexture; +varying lowp vec4 varColor; +varying mediump vec2 varTexCoord; + void main(void) { - vec2 uv = gl_TexCoord[0].st; + vec2 uv = varTexCoord.st; vec4 color = texture2D(baseTexture, uv); - color.rgb *= gl_Color.rgb; + color.rgb *= varColor.rgb; gl_FragColor = color; } diff --git a/client/shaders/selection_shader/opengl_vertex.glsl b/client/shaders/selection_shader/opengl_vertex.glsl index d0b16c8b0..9ca87a9cf 100644 --- a/client/shaders/selection_shader/opengl_vertex.glsl +++ b/client/shaders/selection_shader/opengl_vertex.glsl @@ -1,9 +1,10 @@ -uniform mat4 mWorldViewProj; +varying lowp vec4 varColor; +varying mediump vec2 varTexCoord; void main(void) { - gl_TexCoord[0] = gl_MultiTexCoord0; - gl_Position = mWorldViewProj * gl_Vertex; + varTexCoord = inTexCoord0.st; + gl_Position = mWorldViewProj * inVertexPosition; - gl_FrontColor = gl_BackColor = gl_Color; + varColor = inVertexColor; } diff --git a/games/devtest/mods/basenodes/init.lua b/games/devtest/mods/basenodes/init.lua index 7ffbadbea..0cb85d808 100644 --- a/games/devtest/mods/basenodes/init.lua +++ b/games/devtest/mods/basenodes/init.lua @@ -127,6 +127,7 @@ minetest.register_node("basenodes:water_source", { description = "Water Source".."\n".. "Drowning damage: 1", drawtype = "liquid", + waving = 3, tiles = {"default_water.png"}, special_tiles = { {name = "default_water.png", backface_culling = false}, @@ -152,6 +153,7 @@ minetest.register_node("basenodes:water_flowing", { description = "Flowing Water".."\n".. "Drowning damage: 1", drawtype = "flowingliquid", + waving = 3, tiles = {"default_water_flowing.png"}, special_tiles = { {name = "default_water_flowing.png", backface_culling = false}, @@ -178,6 +180,7 @@ minetest.register_node("basenodes:river_water_source", { description = "River Water Source".."\n".. "Drowning damage: 1", drawtype = "liquid", + waving = 3, tiles = { "default_river_water.png" }, special_tiles = { {name = "default_river_water.png", backface_culling = false}, @@ -205,6 +208,7 @@ minetest.register_node("basenodes:river_water_flowing", { description = "Flowing River Water".."\n".. "Drowning damage: 1", drawtype = "flowingliquid", + waving = 3, tiles = {"default_river_water_flowing.png"}, special_tiles = { {name = "default_river_water_flowing.png", backface_culling = false}, diff --git a/src/client/shader.cpp b/src/client/shader.cpp index e2eeb4ab0..f2aa00246 100644 --- a/src/client/shader.cpp +++ b/src/client/shader.cpp @@ -37,6 +37,7 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "log.h" #include "gamedef.h" #include "client/tile.h" +#include "config.h" #if ENABLE_GLES #ifdef _IRR_COMPILE_WITH_OGLES1_ @@ -230,11 +231,24 @@ class MainShaderConstantSetter : public IShaderConstantSetter { CachedVertexShaderSetting m_world_view_proj; CachedVertexShaderSetting m_world; +#if ENABLE_GLES + // Modelview matrix + CachedVertexShaderSetting m_world_view; + // Texture matrix + CachedVertexShaderSetting m_texture; + // Normal matrix + CachedVertexShaderSetting m_normal; +#endif public: MainShaderConstantSetter() : - m_world_view_proj("mWorldViewProj"), - m_world("mWorld") + m_world_view_proj("mWorldViewProj") + , m_world("mWorld") +#if ENABLE_GLES + , m_world_view("mWorldView") + , m_texture("mTexture") + , m_normal("mNormal") +#endif {} ~MainShaderConstantSetter() = default; @@ -244,16 +258,6 @@ public: video::IVideoDriver *driver = services->getVideoDriver(); sanity_check(driver); - // Set clip matrix - core::matrix4 worldViewProj; - worldViewProj = driver->getTransform(video::ETS_PROJECTION); - worldViewProj *= driver->getTransform(video::ETS_VIEW); - worldViewProj *= driver->getTransform(video::ETS_WORLD); - if (is_highlevel) - m_world_view_proj.set(*reinterpret_cast(worldViewProj.pointer()), services); - else - services->setVertexShaderConstant(worldViewProj.pointer(), 0, 4); - // Set world matrix core::matrix4 world = driver->getTransform(video::ETS_WORLD); if (is_highlevel) @@ -261,6 +265,35 @@ public: else services->setVertexShaderConstant(world.pointer(), 4, 4); + // Set clip matrix + core::matrix4 worldView; + worldView = driver->getTransform(video::ETS_VIEW); + worldView *= world; + core::matrix4 worldViewProj; + worldViewProj = driver->getTransform(video::ETS_PROJECTION); + worldViewProj *= worldView; + if (is_highlevel) + m_world_view_proj.set(*reinterpret_cast(worldViewProj.pointer()), services); + else + services->setVertexShaderConstant(worldViewProj.pointer(), 0, 4); + +#if ENABLE_GLES + if (is_highlevel) { + core::matrix4 texture = driver->getTransform(video::ETS_TEXTURE_0); + m_world_view.set(*reinterpret_cast(worldView.pointer()), services); + m_texture.set(*reinterpret_cast(texture.pointer()), services); + + core::matrix4 normal; + worldView.getTransposed(normal); + sanity_check(normal.makeInverse()); + float m[9] = { + normal[0], normal[1], normal[2], + normal[4], normal[5], normal[6], + normal[8], normal[9], normal[10], + }; + m_normal.set(m, services); + } +#endif } }; @@ -620,15 +653,62 @@ ShaderInfo generate_shader(const std::string &name, u8 material_type, u8 drawtyp return shaderinfo; // Create shaders header - std::string shaders_header = "#version 120\n"; + bool use_gles = false; +#if ENABLE_GLES + use_gles = driver->getDriverType() == video::EDT_OGLES2; +#endif + std::string shaders_header, vertex_header, pixel_header; // geometry shaders aren’t supported in GLES<3 + if (use_gles) { + shaders_header = + "#version 100\n" + ; + vertex_header = R"( + uniform highp mat4 mWorldView; + uniform highp mat4 mWorldViewProj; + uniform mediump mat4 mTexture; + uniform mediump mat3 mNormal; + attribute highp vec4 inVertexPosition; + attribute lowp vec4 inVertexColor; + attribute mediump vec4 inTexCoord0; + attribute mediump vec3 inVertexNormal; + attribute mediump vec4 inVertexTangent; + attribute mediump vec4 inVertexBinormal; + )"; + pixel_header = R"( + precision mediump float; + )"; + } else { + shaders_header = R"( + #version 120 + #define lowp + #define mediump + #define highp + )"; + vertex_header = R"( + #define mWorldView gl_ModelViewMatrix + #define mWorldViewProj gl_ModelViewProjectionMatrix + #define mTexture (gl_TextureMatrix[0]) + #define mNormal gl_NormalMatrix + + #define inVertexPosition gl_Vertex + #define inVertexColor gl_Color + #define inTexCoord0 gl_MultiTexCoord0 + #define inVertexNormal gl_Normal + #define inVertexTangent gl_MultiTexCoord1 + #define inVertexBinormal gl_MultiTexCoord2 + )"; + } + + bool use_discard = use_gles; #ifdef __unix__ // For renderers that should use discard instead of GL_ALPHA_TEST const char* gl_renderer = (const char*)glGetString(GL_RENDERER); - if (strstr(gl_renderer, "GC7000")) { - shaders_header += "#define USE_DISCARD\n"; - } + if (strstr(gl_renderer, "GC7000")) + use_discard = true; #endif + if (use_discard && shaderinfo.base_material != video::EMT_SOLID) + shaders_header += "#define USE_DISCARD\n"; static const char* drawTypes[] = { "NDT_NORMAL", @@ -654,7 +734,7 @@ ShaderInfo generate_shader(const std::string &name, u8 material_type, u8 drawtyp shaders_header += "#define "; shaders_header += drawTypes[i]; shaders_header += " "; - shaders_header += itos(i); + shaders_header += std::to_string(i); shaders_header += "\n"; } @@ -677,27 +757,27 @@ ShaderInfo generate_shader(const std::string &name, u8 material_type, u8 drawtyp shaders_header += "#define "; shaders_header += materialTypes[i]; shaders_header += " "; - shaders_header += itos(i); + shaders_header += std::to_string(i); shaders_header += "\n"; } shaders_header += "#define MATERIAL_TYPE "; - shaders_header += itos(material_type); + shaders_header += std::to_string(material_type); shaders_header += "\n"; shaders_header += "#define DRAW_TYPE "; - shaders_header += itos(drawtype); + shaders_header += std::to_string(drawtype); shaders_header += "\n"; if (g_settings->getBool("enable_waving_water")){ shaders_header += "#define ENABLE_WAVING_WATER 1\n"; shaders_header += "#define WATER_WAVE_HEIGHT "; - shaders_header += ftos(g_settings->getFloat("water_wave_height")); + shaders_header += std::to_string(g_settings->getFloat("water_wave_height")); shaders_header += "\n"; shaders_header += "#define WATER_WAVE_LENGTH "; - shaders_header += ftos(g_settings->getFloat("water_wave_length")); + shaders_header += std::to_string(g_settings->getFloat("water_wave_length")); shaders_header += "\n"; shaders_header += "#define WATER_WAVE_SPEED "; - shaders_header += ftos(g_settings->getFloat("water_wave_speed")); + shaders_header += std::to_string(g_settings->getFloat("water_wave_speed")); shaders_header += "\n"; } else{ shaders_header += "#define ENABLE_WAVING_WATER 0\n"; @@ -719,7 +799,7 @@ ShaderInfo generate_shader(const std::string &name, u8 material_type, u8 drawtyp shaders_header += "#define ENABLE_TONE_MAPPING\n"; shaders_header += "#define FOG_START "; - shaders_header += ftos(rangelim(g_settings->getFloat("fog_start"), 0.0f, 0.99f)); + shaders_header += std::to_string(rangelim(g_settings->getFloat("fog_start"), 0.0f, 0.99f)); shaders_header += "\n"; // Call addHighLevelShaderMaterial() or addShaderMaterial() @@ -727,11 +807,11 @@ ShaderInfo generate_shader(const std::string &name, u8 material_type, u8 drawtyp const c8* pixel_program_ptr = 0; const c8* geometry_program_ptr = 0; if (!vertex_program.empty()) { - vertex_program = shaders_header + vertex_program; + vertex_program = shaders_header + vertex_header + vertex_program; vertex_program_ptr = vertex_program.c_str(); } if (!pixel_program.empty()) { - pixel_program = shaders_header + pixel_program; + pixel_program = shaders_header + pixel_header + pixel_program; pixel_program_ptr = pixel_program.c_str(); } if (!geometry_program.empty()) { @@ -813,27 +893,37 @@ void load_shaders(const std::string &name, SourceShaderCache *sourcecache, geometry_program = ""; is_highlevel = false; - if(enable_shaders){ - // Look for high level shaders - if(drivertype == video::EDT_DIRECT3D9){ - // Direct3D 9: HLSL - // (All shaders in one file) - vertex_program = sourcecache->getOrLoad(name, "d3d9.hlsl"); - pixel_program = vertex_program; - geometry_program = vertex_program; - } - else if(drivertype == video::EDT_OPENGL){ - // OpenGL: GLSL - vertex_program = sourcecache->getOrLoad(name, "opengl_vertex.glsl"); - pixel_program = sourcecache->getOrLoad(name, "opengl_fragment.glsl"); - geometry_program = sourcecache->getOrLoad(name, "opengl_geometry.glsl"); - } - if (!vertex_program.empty() || !pixel_program.empty() || !geometry_program.empty()){ - is_highlevel = true; - return; - } - } + if (!enable_shaders) + return; + // Look for high level shaders + switch (drivertype) { + case video::EDT_DIRECT3D9: + // Direct3D 9: HLSL + // (All shaders in one file) + vertex_program = sourcecache->getOrLoad(name, "d3d9.hlsl"); + pixel_program = vertex_program; + geometry_program = vertex_program; + break; + + case video::EDT_OPENGL: +#if ENABLE_GLES + case video::EDT_OGLES2: +#endif + // OpenGL: GLSL + vertex_program = sourcecache->getOrLoad(name, "opengl_vertex.glsl"); + pixel_program = sourcecache->getOrLoad(name, "opengl_fragment.glsl"); + geometry_program = sourcecache->getOrLoad(name, "opengl_geometry.glsl"); + break; + + default: + // e.g. OpenGL ES 1 (with no shader support) + break; + } + if (!vertex_program.empty() || !pixel_program.empty() || !geometry_program.empty()){ + is_highlevel = true; + return; + } } void dumpShaderProgram(std::ostream &output_stream,