From bbd6f8cf249f11113c280a12c497646870a6bd84 Mon Sep 17 00:00:00 2001 From: Anstro Pleuton <anstropleuton@github.com> Date: Wed, 22 Jan 2025 04:52:09 -0800 Subject: [PATCH] Combine shaders --- .../shaders/glsl100/rounded_rectangle.fs | 65 ++--- .../glsl100/rounded_rectangle_border.fs | 91 ------ .../glsl100/rounded_rectangle_shadow.fs | 98 ------- .../shaders/glsl120/rounded_rectangle.fs | 72 +++-- .../glsl120/rounded_rectangle_border.fs | 89 ------ .../glsl120/rounded_rectangle_shadow.fs | 96 ------- .../shaders/glsl330/rounded_rectangle.fs | 72 +++-- .../glsl330/rounded_rectangle_border.fs | 92 ------ .../glsl330/rounded_rectangle_shadow.fs | 99 ------- examples/shaders/shaders_rounded_rectangle.c | 266 ++++++++++-------- 10 files changed, 240 insertions(+), 800 deletions(-) delete mode 100644 examples/shaders/resources/shaders/glsl100/rounded_rectangle_border.fs delete mode 100644 examples/shaders/resources/shaders/glsl100/rounded_rectangle_shadow.fs delete mode 100644 examples/shaders/resources/shaders/glsl120/rounded_rectangle_border.fs delete mode 100644 examples/shaders/resources/shaders/glsl120/rounded_rectangle_shadow.fs delete mode 100644 examples/shaders/resources/shaders/glsl330/rounded_rectangle_border.fs delete mode 100644 examples/shaders/resources/shaders/glsl330/rounded_rectangle_shadow.fs diff --git a/examples/shaders/resources/shaders/glsl100/rounded_rectangle.fs b/examples/shaders/resources/shaders/glsl100/rounded_rectangle.fs index c28124d02..565c05835 100644 --- a/examples/shaders/resources/shaders/glsl100/rounded_rectangle.fs +++ b/examples/shaders/resources/shaders/glsl100/rounded_rectangle.fs @@ -14,44 +14,23 @@ uniform vec4 colDiffuse; uniform vec4 rectangle; // Rectangle dimensions (x, y, width, height) uniform vec4 radius; // Corner radius (top-left, top-right, bottom-left, bottom-right) +uniform vec4 color; -// TODO: Remove anti-aliasing? +// Shadow parameters +uniform float shadowRadius; +uniform vec2 shadowOffset; +uniform float shadowScale; +uniform vec4 shadowColor; -// Anti-alias using easing function for smmoth edges -uniform float aaPower; -uniform float aaDistance; - -// Ease in-out -float ease(float x, float p) -{ - if (x < 0.5) - { - return 1.0/pow(0.5, p - 1.0)*pow(x, p); - } - else - { - return 1.0 - 1.0/pow(0.5, p - 1.0)*pow(1.0 - x, p); - } -} - -// Smoothstep with easing -float easestep(float edge0, float edge1, float x, float p) -{ - float t = clamp( (x - edge0)/(edge1 - edge0), 0.0, 1.0 ); - return ease(t, p); -} - -// Anti-alias on edge for x -float antiAlias(float edge, float x) -{ - return easestep(edge + aaDistance*0.5, edge - aaDistance*0.5, x, aaPower); -} +// Border parameters +uniform float borderThickness; +uniform vec4 borderColor; // Create a rounded rectangle using signed distance field // Thanks to Iñigo Quilez (https://www.iquilezles.org/www/articles/distfunctions/distfunctions.htm) // And thanks to inobelar (https://www.shadertoy.com/view/fsdyzB) for shader // MIT License -float roundedRectangleSDF( +float RoundedRectangleSDF( vec2 fragCoord, vec2 center, vec2 halfSize, @@ -74,17 +53,29 @@ void main() // Texel color fetching from texture sampler vec4 texelColor = texture2D(texture0, fragTexCoord); - // Get fragment coordinate in pixels + // Requires fragment coordinate varying pixels vec2 fragCoord = gl_FragCoord.xy; // Calculate signed distance field for rounded rectangle vec2 halfSize = rectangle.zw*0.5; vec2 center = rectangle.xy + halfSize; - float sdf = roundedRectangleSDF(fragCoord, center, halfSize, radius); + float recSDF = RoundedRectangleSDF(fragCoord, center, halfSize, radius); + + // Calculate signed distance field for rectangle shadow + vec2 shadowHalfSize = halfSize*shadowScale; + vec2 shadowCenter = center + shadowOffset; + float shadowSDF = RoundedRectangleSDF(fragCoord, shadowCenter, shadowHalfSize, radius); + + // Caculate alpha factors + float recFactor = smoothstep(1.0, 0.0, recSDF); + float shadowFactor = smoothstep(shadowRadius, 0.0, shadowSDF); + float borderFactor = smoothstep(0.0, 1.0, recSDF + borderThickness)*recFactor; - // Calculate anti-aliased factor - float aa = 1.0 - antiAlias(0.0, -sdf); + // Multiply each color by its respective alpha factor + vec4 recColor = vec4(color.rgb, color.a*recFactor); + vec4 shadowCol = vec4(shadowColor.rgb, shadowColor.a*shadowFactor); + vec4 borderCol = vec4(borderColor.rgb, borderColor.a*borderFactor); - gl_FragColor = texelColor*colDiffuse*fragColor - *vec4(1.0, 1.0, 1.0, aa); + // Combine the colors varying the order (shadow, rectangle, border) + gl_FragColor = mix(mix(shadowCol, recColor, recColor.a), borderCol, borderCol.a); } \ No newline at end of file diff --git a/examples/shaders/resources/shaders/glsl100/rounded_rectangle_border.fs b/examples/shaders/resources/shaders/glsl100/rounded_rectangle_border.fs deleted file mode 100644 index d19876455..000000000 --- a/examples/shaders/resources/shaders/glsl100/rounded_rectangle_border.fs +++ /dev/null @@ -1,91 +0,0 @@ -// Note: SDF by Iñigo Quilez is licensed under MIT License - -#version 100 - -precision mediump float; - -// Input vertex attributes (from vertex shader) -varying vec2 fragTexCoord; -varying vec4 fragColor; - -// Input uniform values -uniform sampler2D texture0; -uniform vec4 colDiffuse; - -uniform vec4 rectangle; // Rectangle dimensions (x, y, width, height) -uniform vec4 radius; // Corner radius (top-left, top-right, bottom-left, bottom-right) -uniform float borderThickness; - -// TODO: Remove anti-aliasing? - -// Anti-alias using easing function for smmoth edges -uniform float aaPower; -uniform float aaDistance; - -// Ease in-out -float ease(float x, float p) -{ - if (x < 0.5) - { - return 1.0/pow(0.5, p - 1.0)*pow(x, p); - } - else - { - return 1.0 - 1.0/pow(0.5, p - 1.0)*pow(1.0 - x, p); - } -} - -// Smoothstep with easing -float easestep(float edge0, float edge1, float x, float p) -{ - float t = clamp( (x - edge0)/(edge1 - edge0), 0.0, 1.0 ); - return ease(t, p); -} - -// Anti-alias on edge for x -float antiAlias(float edge, float x) -{ - return easestep(edge + aaDistance*0.5, edge - aaDistance*0.5, x, aaPower); -} - -// Create a rounded rectangle using signed distance field -// Thanks to Iñigo Quilez (https://www.iquilezles.org/www/articles/distfunctions/distfunctions.htm) -// And thanks to inobelar (https://www.shadertoy.com/view/fsdyzB) for shader -// MIT License -float roundedRectangleSDF( - vec2 fragCoord, - vec2 center, - vec2 halfSize, - vec4 radius -) -{ - vec2 fragFromCenter = fragCoord - center; - - // Determine which corner radius to use - radius.xy = (fragFromCenter.y > 0.0) ? radius.xy : radius.zw; - radius.x = (fragFromCenter.x < 0.0) ? radius.x : radius.y; - - // Calculate signed distance field - vec2 dist = abs(fragFromCenter) - halfSize + radius.x; - return min(max(dist.x, dist.y), 0.0) + length(max(dist, 0.0)) - radius.x; -} - -void main() -{ - // Texel color fetching from texture sampler - vec4 texelColor = texture2D(texture0, fragTexCoord); - - // Get fragment coordinate in pixels - vec2 fragCoord = gl_FragCoord.xy; - - // Calculate signed distance field for rounded rectangle's border - vec2 halfSize = rectangle.zw*0.5; - vec2 center = rectangle.xy + halfSize; - float sdf = roundedRectangleSDF(fragCoord, center, halfSize, radius); - - // Calculate anti-aliased factor - float aa = antiAlias(borderThickness, -sdf) * (1.0 - antiAlias(0.0, -sdf)); - - gl_FragColor = texelColor*colDiffuse*fragColor - *vec4(1.0, 1.0, 1.0, aa); -} \ No newline at end of file diff --git a/examples/shaders/resources/shaders/glsl100/rounded_rectangle_shadow.fs b/examples/shaders/resources/shaders/glsl100/rounded_rectangle_shadow.fs deleted file mode 100644 index 90a1e5e66..000000000 --- a/examples/shaders/resources/shaders/glsl100/rounded_rectangle_shadow.fs +++ /dev/null @@ -1,98 +0,0 @@ -// Note: SDF by Iñigo Quilez is licensed under MIT License - -#version 100 - -precision mediump float; - -// Input vertex attributes (from vertex shader) -varying vec2 fragTexCoord; -varying vec4 fragColor; - -// Input uniform values -uniform sampler2D texture0; -uniform vec4 colDiffuse; - -uniform vec4 rectangle; // Rectangle dimensions (x, y, width, height) -uniform vec4 radius; // Corner radius (top-left, top-right, bottom-left, bottom-right) - -// Shadow parameters -uniform float shadowRadius; -uniform float shadowPower; -uniform vec2 shadowOffset; -uniform float shadowScale; - -// TODO: Remove anti-aliasing? - -// Anti-alias using easing function for smmoth edges -uniform float aaPower; -uniform float aaDistance; - -// Ease in-out -float ease(float x, float p) -{ - if (x < 0.5) - { - return 1.0/pow(0.5, p - 1.0)*pow(x, p); - } - else - { - return 1.0 - 1.0/pow(0.5, p - 1.0)*pow(1.0 - x, p); - } -} - -// Smoothstep with easing -float easestep(float edge0, float edge1, float x, float p) -{ - float t = clamp( (x - edge0)/(edge1 - edge0), 0.0, 1.0 ); - return ease(t, p); -} - -// Anti-alias on edge for x -float antiAlias(float edge, float x) -{ - return easestep(edge + aaDistance*0.5, edge - aaDistance*0.5, x, aaPower); -} - -// Create a rounded rectangle using signed distance field -// Thanks to Iñigo Quilez (https://www.iquilezles.org/www/articles/distfunctions/distfunctions.htm) -// And thanks to inobelar (https://www.shadertoy.com/view/fsdyzB) for shader -// MIT License -float roundedRectangleSDF( - vec2 fragCoord, - vec2 center, - vec2 halfSize, - vec4 radius -) -{ - vec2 fragFromCenter = fragCoord - center; - - // Determine which corner radius to use - radius.xy = (fragFromCenter.y > 0.0) ? radius.xy : radius.zw; - radius.x = (fragFromCenter.x < 0.0) ? radius.x : radius.y; - - // Calculate signed distance field - vec2 dist = abs(fragFromCenter) - halfSize + radius.x; - return min(max(dist.x, dist.y), 0.0) + length(max(dist, 0.0)) - radius.x; -} - -void main() -{ - // Texel color fetching from texture sampler - vec4 texelColor = texture2D(texture0, fragTexCoord); - - // Get fragment coordinate in pixels - vec2 fragCoord = gl_FragCoord.xy; - - // Calculate signed distance field for rounded rectangle's shadow - vec2 halfSize = rectangle.zw*0.5; - vec2 center = rectangle.xy + halfSize; - - vec2 shadowHalfSize = halfSize*shadowScale; - vec2 shadowCenter = center + shadowOffset; - float sdf = roundedRectangleSDF(fragCoord, shadowCenter, shadowHalfSize, radius); - - float aa = easestep(shadowRadius, 0.0, sdf, shadowPower); - - gl_FragColor = texelColor*colDiffuse*fragColor - *vec4(1.0, 1.0, 1.0, aa); -} \ No newline at end of file diff --git a/examples/shaders/resources/shaders/glsl120/rounded_rectangle.fs b/examples/shaders/resources/shaders/glsl120/rounded_rectangle.fs index 70ed29cbd..206f0cf3e 100644 --- a/examples/shaders/resources/shaders/glsl120/rounded_rectangle.fs +++ b/examples/shaders/resources/shaders/glsl120/rounded_rectangle.fs @@ -12,51 +12,29 @@ uniform vec4 colDiffuse; uniform vec4 rectangle; // Rectangle dimensions (x, y, width, height) uniform vec4 radius; // Corner radius (top-left, top-right, bottom-left, bottom-right) +uniform vec4 color; -// TODO: Remove anti-aliasing? +// Shadow parameters +uniform float shadowRadius; +uniform vec2 shadowOffset; +uniform float shadowScale; +uniform vec4 shadowColor; -// Anti-alias using easing function for smmoth edges -uniform float aaPower; -uniform float aaDistance; - -// Ease in-out -float ease(float x, float p) -{ - if (x < 0.5) - { - return 1.0/pow(0.5, p - 1.0)*pow(x, p); - } - else - { - return 1.0 - 1.0/pow(0.5, p - 1.0)*pow(1.0 - x, p); - } -} - -// Smoothstep with easing -float easestep(float edge0, float edge1, float x, float p) -{ - float t = clamp( (x - edge0)/(edge1 - edge0), 0.0, 1.0 ); - return ease(t, p); -} - -// Anti-alias on edge for x -float antiAlias(float edge, float x) -{ - return easestep(edge + aaDistance*0.5, edge - aaDistance*0.5, x, aaPower); -} +// Border parameters +uniform float borderThickness; +uniform vec4 borderColor; // Create a rounded rectangle using signed distance field // Thanks to Iñigo Quilez (https://www.iquilezles.org/www/articles/distfunctions/distfunctions.htm) // And thanks to inobelar (https://www.shadertoy.com/view/fsdyzB) for shader // MIT License -float roundedRectangleSDF( +float RoundedRectangleSDF( vec2 fragCoord, - vec4 rectangle, + vec2 center, + vec2 halfSize, vec4 radius ) { - vec2 halfSize = rectangle.zw*0.5; - vec2 center = rectangle.xy + halfSize; vec2 fragFromCenter = fragCoord - center; // Determine which corner radius to use @@ -73,15 +51,29 @@ void main() // Texel color fetching from texture sampler vec4 texelColor = texture2D(texture0, fragTexCoord); - // Get fragment coordinate in pixels + // Requires fragment coordinate varying pixels vec2 fragCoord = gl_FragCoord.xy; // Calculate signed distance field for rounded rectangle - float sdf = roundedRectangleSDF(fragCoord, rectangle, radius); + vec2 halfSize = rectangle.zw*0.5; + vec2 center = rectangle.xy + halfSize; + float recSDF = RoundedRectangleSDF(fragCoord, center, halfSize, radius); + + // Calculate signed distance field for rectangle shadow + vec2 shadowHalfSize = halfSize*shadowScale; + vec2 shadowCenter = center + shadowOffset; + float shadowSDF = RoundedRectangleSDF(fragCoord, shadowCenter, shadowHalfSize, radius); + + // Caculate alpha factors + float recFactor = smoothstep(1.0, 0.0, recSDF); + float shadowFactor = smoothstep(shadowRadius, 0.0, shadowSDF); + float borderFactor = smoothstep(0.0, 1.0, recSDF + borderThickness)*recFactor; - // Calculate anti-aliased factor - float aa = 1.0 - antiAlias(0.0, -sdf); + // Multiply each color by its respective alpha factor + vec4 recColor = vec4(color.rgb, color.a*recFactor); + vec4 shadowCol = vec4(shadowColor.rgb, shadowColor.a*shadowFactor); + vec4 borderCol = vec4(borderColor.rgb, borderColor.a*borderFactor); - gl_FragColor = texelColor*colDiffuse*fragColor - *vec4(1.0, 1.0, 1.0, aa); + // Combine the colors varying the order (shadow, rectangle, border) + gl_FragColor = mix(mix(shadowCol, recColor, recColor.a), borderCol, borderCol.a); } \ No newline at end of file diff --git a/examples/shaders/resources/shaders/glsl120/rounded_rectangle_border.fs b/examples/shaders/resources/shaders/glsl120/rounded_rectangle_border.fs deleted file mode 100644 index 66d453d2f..000000000 --- a/examples/shaders/resources/shaders/glsl120/rounded_rectangle_border.fs +++ /dev/null @@ -1,89 +0,0 @@ -// Note: SDF by Iñigo Quilez is licensed under MIT License - -#version 120 - -// Input vertex attributes (from vertex shader) -varying vec2 fragTexCoord; -varying vec4 fragColor; - -// Input uniform values -uniform sampler2D texture0; -uniform vec4 colDiffuse; - -uniform vec4 rectangle; // Rectangle dimensions (x, y, width, height) -uniform vec4 radius; // Corner radius (top-left, top-right, bottom-left, bottom-right) -uniform float borderThickness; - -// TODO: Remove anti-aliasing? - -// Anti-alias using easing function for smmoth edges -uniform float aaPower; -uniform float aaDistance; - -// Ease in-out -float ease(float x, float p) -{ - if (x < 0.5) - { - return 1.0/pow(0.5, p - 1.0)*pow(x, p); - } - else - { - return 1.0 - 1.0/pow(0.5, p - 1.0)*pow(1.0 - x, p); - } -} - -// Smoothstep with easing -float easestep(float edge0, float edge1, float x, float p) -{ - float t = clamp( (x - edge0)/(edge1 - edge0), 0.0, 1.0 ); - return ease(t, p); -} - -// Anti-alias on edge for x -float antiAlias(float edge, float x) -{ - return easestep(edge + aaDistance*0.5, edge - aaDistance*0.5, x, aaPower); -} - -// Create a rounded rectangle using signed distance field -// Thanks to Iñigo Quilez (https://www.iquilezles.org/www/articles/distfunctions/distfunctions.htm) -// And thanks to inobelar (https://www.shadertoy.com/view/fsdyzB) for shader -// MIT License -float roundedRectangleSDF( - vec2 fragCoord, - vec2 center, - vec2 halfSize, - vec4 radius -) -{ - vec2 fragFromCenter = fragCoord - center; - - // Determine which corner radius to use - radius.xy = (fragFromCenter.y > 0.0) ? radius.xy : radius.zw; - radius.x = (fragFromCenter.x < 0.0) ? radius.x : radius.y; - - // Calculate signed distance field - vec2 dist = abs(fragFromCenter) - halfSize + radius.x; - return min(max(dist.x, dist.y), 0.0) + length(max(dist, 0.0)) - radius.x; -} - -void main() -{ - // Texel color fetching from texture sampler - vec4 texelColor = texture2D(texture0, fragTexCoord); - - // Get fragment coordinate in pixels - vec2 fragCoord = gl_FragCoord.xy; - - // Calculate signed distance field for rounded rectangle's border - vec2 halfSize = rectangle.zw*0.5; - vec2 center = rectangle.xy + halfSize; - float sdf = roundedRectangleSDF(fragCoord, center, halfSize, radius); - - // Calculate anti-aliased factor - float aa = antiAlias(borderThickness, -sdf) * (1.0 - antiAlias(0.0, -sdf)); - - gl_FragColor = texelColor*colDiffuse*fragColor - *vec4(1.0, 1.0, 1.0, aa); -} \ No newline at end of file diff --git a/examples/shaders/resources/shaders/glsl120/rounded_rectangle_shadow.fs b/examples/shaders/resources/shaders/glsl120/rounded_rectangle_shadow.fs deleted file mode 100644 index e06e3fff3..000000000 --- a/examples/shaders/resources/shaders/glsl120/rounded_rectangle_shadow.fs +++ /dev/null @@ -1,96 +0,0 @@ -// Note: SDF by Iñigo Quilez is licensed under MIT License - -#version 120 - -// Input vertex attributes (from vertex shader) -varying vec2 fragTexCoord; -varying vec4 fragColor; - -// Input uniform values -uniform sampler2D texture0; -uniform vec4 colDiffuse; - -uniform vec4 rectangle; // Rectangle dimensions (x, y, width, height) -uniform vec4 radius; // Corner radius (top-left, top-right, bottom-left, bottom-right) - -// Shadow parameters -uniform float shadowRadius; -uniform float shadowPower; -uniform vec2 shadowOffset; -uniform float shadowScale; - -// TODO: Remove anti-aliasing? - -// Anti-alias using easing function for smmoth edges -uniform float aaPower; -uniform float aaDistance; - -// Ease in-out -float ease(float x, float p) -{ - if (x < 0.5) - { - return 1.0/pow(0.5, p - 1.0)*pow(x, p); - } - else - { - return 1.0 - 1.0/pow(0.5, p - 1.0)*pow(1.0 - x, p); - } -} - -// Smoothstep with easing -float easestep(float edge0, float edge1, float x, float p) -{ - float t = clamp( (x - edge0)/(edge1 - edge0), 0.0, 1.0 ); - return ease(t, p); -} - -// Anti-alias on edge for x -float antiAlias(float edge, float x) -{ - return easestep(edge + aaDistance*0.5, edge - aaDistance*0.5, x, aaPower); -} - -// Create a rounded rectangle using signed distance field -// Thanks to Iñigo Quilez (https://www.iquilezles.org/www/articles/distfunctions/distfunctions.htm) -// And thanks to inobelar (https://www.shadertoy.com/view/fsdyzB) for shader -// MIT License -float roundedRectangleSDF( - vec2 fragCoord, - vec2 center, - vec2 halfSize, - vec4 radius -) -{ - vec2 fragFromCenter = fragCoord - center; - - // Determine which corner radius to use - radius.xy = (fragFromCenter.y > 0.0) ? radius.xy : radius.zw; - radius.x = (fragFromCenter.x < 0.0) ? radius.x : radius.y; - - // Calculate signed distance field - vec2 dist = abs(fragFromCenter) - halfSize + radius.x; - return min(max(dist.x, dist.y), 0.0) + length(max(dist, 0.0)) - radius.x; -} - -void main() -{ - // Texel color fetching from texture sampler - vec4 texelColor = texture2D(texture0, fragTexCoord); - - // Get fragment coordinate in pixels - vec2 fragCoord = gl_FragCoord.xy; - - // Calculate signed distance field for rounded rectangle's shadow - vec2 halfSize = rectangle.zw*0.5; - vec2 center = rectangle.xy + halfSize; - - vec2 shadowHalfSize = halfSize*shadowScale; - vec2 shadowCenter = center + shadowOffset; - float sdf = roundedRectangleSDF(fragCoord, shadowCenter, shadowHalfSize, radius); - - float aa = easestep(shadowRadius, 0.0, sdf, shadowPower); - - gl_FragColor = texelColor*colDiffuse*fragColor - *vec4(1.0, 1.0, 1.0, aa); -} \ No newline at end of file diff --git a/examples/shaders/resources/shaders/glsl330/rounded_rectangle.fs b/examples/shaders/resources/shaders/glsl330/rounded_rectangle.fs index e707aa8c3..277a6ebeb 100644 --- a/examples/shaders/resources/shaders/glsl330/rounded_rectangle.fs +++ b/examples/shaders/resources/shaders/glsl330/rounded_rectangle.fs @@ -15,51 +15,29 @@ out vec4 finalColor; uniform vec4 rectangle; // Rectangle dimensions (x, y, width, height) uniform vec4 radius; // Corner radius (top-left, top-right, bottom-left, bottom-right) +uniform vec4 color; -// TODO: Remove anti-aliasing? +// Shadow parameters +uniform float shadowRadius; +uniform vec2 shadowOffset; +uniform float shadowScale; +uniform vec4 shadowColor; -// Anti-alias using easing function for smmoth edges -uniform float aaPower; -uniform float aaDistance; - -// Ease in-out -float ease(float x, float p) -{ - if (x < 0.5) - { - return 1.0/pow(0.5, p - 1.0)*pow(x, p); - } - else - { - return 1.0 - 1.0/pow(0.5, p - 1.0)*pow(1.0 - x, p); - } -} - -// Smoothstep with easing -float easestep(float edge0, float edge1, float x, float p) -{ - float t = clamp( (x - edge0)/(edge1 - edge0), 0.0, 1.0 ); - return ease(t, p); -} - -// Anti-alias on edge for x -float antiAlias(float edge, float x) -{ - return easestep(edge + aaDistance*0.5, edge - aaDistance*0.5, x, aaPower); -} +// Border parameters +uniform float borderThickness; +uniform vec4 borderColor; // Create a rounded rectangle using signed distance field // Thanks to Iñigo Quilez (https://www.iquilezles.org/www/articles/distfunctions/distfunctions.htm) // And thanks to inobelar (https://www.shadertoy.com/view/fsdyzB) for shader // MIT License -float roundedRectangleSDF( +float RoundedRectangleSDF( vec2 fragCoord, - vec4 rectangle, + vec2 center, + vec2 halfSize, vec4 radius ) { - vec2 halfSize = rectangle.zw*0.5; - vec2 center = rectangle.xy + halfSize; vec2 fragFromCenter = fragCoord - center; // Determine which corner radius to use @@ -76,15 +54,29 @@ void main() // Texel color fetching from texture sampler vec4 texelColor = texture(texture0, fragTexCoord); - // Get fragment coordinate in pixels + // Requires fragment coordinate in pixels vec2 fragCoord = gl_FragCoord.xy; // Calculate signed distance field for rounded rectangle - float sdf = roundedRectangleSDF(fragCoord, rectangle, radius); + vec2 halfSize = rectangle.zw*0.5; + vec2 center = rectangle.xy + halfSize; + float recSDF = RoundedRectangleSDF(fragCoord, center, halfSize, radius); + + // Calculate signed distance field for rectangle shadow + vec2 shadowHalfSize = halfSize*shadowScale; + vec2 shadowCenter = center + shadowOffset; + float shadowSDF = RoundedRectangleSDF(fragCoord, shadowCenter, shadowHalfSize, radius); + + // Caculate alpha factors + float recFactor = smoothstep(1.0, 0.0, recSDF); + float shadowFactor = smoothstep(shadowRadius, 0.0, shadowSDF); + float borderFactor = smoothstep(0.0, 1.0, recSDF + borderThickness)*recFactor; - // Calculate anti-aliased factor - float aa = 1.0 - antiAlias(0.0, -sdf); + // Multiply each color by its respective alpha factor + vec4 recColor = vec4(color.rgb, color.a*recFactor); + vec4 shadowCol = vec4(shadowColor.rgb, shadowColor.a*shadowFactor); + vec4 borderCol = vec4(borderColor.rgb, borderColor.a*borderFactor); - finalColor = texelColor*colDiffuse*fragColor - *vec4(1.0, 1.0, 1.0, aa); + // Combine the colors in the order (shadow, rectangle, border) + finalColor = mix(mix(shadowCol, recColor, recColor.a), borderCol, borderCol.a); } \ No newline at end of file diff --git a/examples/shaders/resources/shaders/glsl330/rounded_rectangle_border.fs b/examples/shaders/resources/shaders/glsl330/rounded_rectangle_border.fs deleted file mode 100644 index 0e27bee4f..000000000 --- a/examples/shaders/resources/shaders/glsl330/rounded_rectangle_border.fs +++ /dev/null @@ -1,92 +0,0 @@ -// Note: SDF by Iñigo Quilez is licensed under MIT License - -#version 330 - -// Input vertex attributes (from vertex shader) -in vec2 fragTexCoord; -in vec4 fragColor; - -// Input uniform values -uniform sampler2D texture0; -uniform vec4 colDiffuse; - -// Output fragment color -out vec4 finalColor; - -uniform vec4 rectangle; // Rectangle dimensions (x, y, width, height) -uniform vec4 radius; // Corner radius (top-left, top-right, bottom-left, bottom-right) -uniform float borderThickness; - -// TODO: Remove anti-aliasing? - -// Anti-alias using easing function for smmoth edges -uniform float aaPower; -uniform float aaDistance; - -// Ease in-out -float ease(float x, float p) -{ - if (x < 0.5) - { - return 1.0/pow(0.5, p - 1.0)*pow(x, p); - } - else - { - return 1.0 - 1.0/pow(0.5, p - 1.0)*pow(1.0 - x, p); - } -} - -// Smoothstep with easing -float easestep(float edge0, float edge1, float x, float p) -{ - float t = clamp( (x - edge0)/(edge1 - edge0), 0.0, 1.0 ); - return ease(t, p); -} - -// Anti-alias on edge for x -float antiAlias(float edge, float x) -{ - return easestep(edge + aaDistance*0.5, edge - aaDistance*0.5, x, aaPower); -} - -// Create a rounded rectangle using signed distance field -// Thanks to Iñigo Quilez (https://www.iquilezles.org/www/articles/distfunctions/distfunctions.htm) -// And thanks to inobelar (https://www.shadertoy.com/view/fsdyzB) for shader -// MIT License -float roundedRectangleSDF( - vec2 fragCoord, - vec2 center, - vec2 halfSize, - vec4 radius -) -{ - vec2 fragFromCenter = fragCoord - center; - - // Determine which corner radius to use - radius.xy = (fragFromCenter.y > 0.0) ? radius.xy : radius.zw; - radius.x = (fragFromCenter.x < 0.0) ? radius.x : radius.y; - - // Calculate signed distance field - vec2 dist = abs(fragFromCenter) - halfSize + radius.x; - return min(max(dist.x, dist.y), 0.0) + length(max(dist, 0.0)) - radius.x; -} - -void main() -{ - // Texel color fetching from texture sampler - vec4 texelColor = texture(texture0, fragTexCoord); - - // Get fragment coordinate in pixels - vec2 fragCoord = gl_FragCoord.xy; - - // Calculate signed distance field for rounded rectangle's border - vec2 halfSize = rectangle.zw*0.5; - vec2 center = rectangle.xy + halfSize; - float sdf = roundedRectangleSDF(fragCoord, center, halfSize, radius); - - // Calculate anti-aliased factor - float aa = antiAlias(borderThickness, -sdf) * (1.0 - antiAlias(0.0, -sdf)); - - finalColor = texelColor*colDiffuse*fragColor - *vec4(1.0, 1.0, 1.0, aa); -} \ No newline at end of file diff --git a/examples/shaders/resources/shaders/glsl330/rounded_rectangle_shadow.fs b/examples/shaders/resources/shaders/glsl330/rounded_rectangle_shadow.fs deleted file mode 100644 index d02091292..000000000 --- a/examples/shaders/resources/shaders/glsl330/rounded_rectangle_shadow.fs +++ /dev/null @@ -1,99 +0,0 @@ -// Note: SDF by Iñigo Quilez is licensed under MIT License - -#version 330 - -// Input vertex attributes (from vertex shader) -in vec2 fragTexCoord; -in vec4 fragColor; - -// Input uniform values -uniform sampler2D texture0; -uniform vec4 colDiffuse; - -// Output fragment color -out vec4 finalColor; - -uniform vec4 rectangle; // Rectangle dimensions (x, y, width, height) -uniform vec4 radius; // Corner radius (top-left, top-right, bottom-left, bottom-right) - -// Shadow parameters -uniform float shadowRadius; -uniform float shadowPower; -uniform vec2 shadowOffset; -uniform float shadowScale; - -// TODO: Remove anti-aliasing? - -// Anti-alias using easing function for smmoth edges -uniform float aaPower; -uniform float aaDistance; - -// Ease in-out -float ease(float x, float p) -{ - if (x < 0.5) - { - return 1.0/pow(0.5, p - 1.0)*pow(x, p); - } - else - { - return 1.0 - 1.0/pow(0.5, p - 1.0)*pow(1.0 - x, p); - } -} - -// Smoothstep with easing -float easestep(float edge0, float edge1, float x, float p) -{ - float t = clamp( (x - edge0)/(edge1 - edge0), 0.0, 1.0 ); - return ease(t, p); -} - -// Anti-alias on edge for x -float antiAlias(float edge, float x) -{ - return easestep(edge + aaDistance*0.5, edge - aaDistance*0.5, x, aaPower); -} - -// Create a rounded rectangle using signed distance field -// Thanks to Iñigo Quilez (https://www.iquilezles.org/www/articles/distfunctions/distfunctions.htm) -// And thanks to inobelar (https://www.shadertoy.com/view/fsdyzB) for shader -// MIT License -float roundedRectangleSDF( - vec2 fragCoord, - vec2 center, - vec2 halfSize, - vec4 radius -) -{ - vec2 fragFromCenter = fragCoord - center; - - // Determine which corner radius to use - radius.xy = (fragFromCenter.y > 0.0) ? radius.xy : radius.zw; - radius.x = (fragFromCenter.x < 0.0) ? radius.x : radius.y; - - // Calculate signed distance field - vec2 dist = abs(fragFromCenter) - halfSize + radius.x; - return min(max(dist.x, dist.y), 0.0) + length(max(dist, 0.0)) - radius.x; -} - -void main() -{ - // Texel color fetching from texture sampler - vec4 texelColor = texture(texture0, fragTexCoord); - - // Get fragment coordinate in pixels - vec2 fragCoord = gl_FragCoord.xy; - - // Calculate signed distance field for rounded rectangle's shadow - vec2 halfSize = rectangle.zw*0.5; - vec2 center = rectangle.xy + halfSize; - - vec2 shadowHalfSize = halfSize*shadowScale; - vec2 shadowCenter = center + shadowOffset; - float sdf = roundedRectangleSDF(fragCoord, shadowCenter, shadowHalfSize, radius); - - float aa = easestep(shadowRadius, 0.0, sdf, shadowPower); - - finalColor = texelColor*colDiffuse*fragColor - *vec4(1.0, 1.0, 1.0, aa); -} \ No newline at end of file diff --git a/examples/shaders/shaders_rounded_rectangle.c b/examples/shaders/shaders_rounded_rectangle.c index 9e861c0b2..a55680431 100644 --- a/examples/shaders/shaders_rounded_rectangle.c +++ b/examples/shaders/shaders_rounded_rectangle.c @@ -23,6 +23,44 @@ #define GLSL_VERSION 100 #endif +//------------------------------------------------------------------------------------ +// Declare custom Structs +//------------------------------------------------------------------------------------ + +// Rounded rectangle data +typedef struct { + Vector4 cornerRadius; // Individual corner radius (top-left, top-right, bottom-left, bottom-right) + + // Shadow variables + float shadowRadius; + Vector2 shadowOffset; + float shadowScale; + + // Border variables + float borderThickness; // Inner-border thickness + + // Shader locations + int rectangleLoc; + int radiusLoc; + int colorLoc; + int shadowRadiusLoc; + int shadowOffsetLoc; + int shadowScaleLoc; + int shadowColorLoc; + int borderThicknessLoc; + int borderColorLoc; +} RoundedRectangle; + +//------------------------------------------------------------------------------------ +// Module Functions Declaration +//------------------------------------------------------------------------------------ + +// Create a rounded rectangle and set uniform locations +static RoundedRectangle CreateRoundedRectangle(Vector4 cornerRadius, float shadowRadius, Vector2 shadowOffset, float shadowScale, float borderThickness, Shader shader); + +// Update rounded rectangle uniforms +static void UpdateRoundedRectangle(RoundedRectangle rec, Shader shader); + //------------------------------------------------------------------------------------ // Program main entry point //------------------------------------------------------------------------------------ @@ -33,76 +71,28 @@ int main(void) const int screenWidth = 800; const int screenHeight = 450; - SetConfigFlags(FLAG_MSAA_4X_HINT); // Enable Multi Sampling Anti Aliasing 4x (if available) + const Color rectangleColor = BLUE; + const Color shadowColor = DARKBLUE; + const Color borderColor = SKYBLUE; + InitWindow(screenWidth, screenHeight, "raylib [shaders] example - Rounded Rectangle"); - // Shader loading - //-------------------------------------------------------------------------------------- - // Load the rectangle shader which will draw the rectangle with rounded corners - Shader rectangleShader = LoadShader(TextFormat("resources/shaders/glsl%i/base.vs", GLSL_VERSION), - TextFormat("resources/shaders/glsl%i/rounded_rectangle.fs", GLSL_VERSION)); - - // Organized into an array for easy access - int rectangleShaderLocs[4] = { - GetShaderLocation(rectangleShader, "rectangle"), // vec4, rectangle bounds (x, y, width, height, NOTE: Y axis is flipped) - GetShaderLocation(rectangleShader, "radius"), // vec4, radius corners (top-left, top-right, bottom-left, bottom-right) - GetShaderLocation(rectangleShader, "aaPower"), // float, anti-aliasing power - GetShaderLocation(rectangleShader, "aaDistance") // float, anti-aliasing distance - }; - - // Load the rectangle shadow shader which will draw the rectangle's shadow - Shader rectangleShadowShader = LoadShader(TextFormat("resources/shaders/glsl%i/base.vs", GLSL_VERSION), - TextFormat("resources/shaders/glsl%i/rounded_rectangle_shadow.fs", GLSL_VERSION)); - - int rectangleShadowShaderLocs[8] = { - GetShaderLocation(rectangleShadowShader, "rectangle"), // vec4, rectangle bounds (x, y, width, height) - GetShaderLocation(rectangleShadowShader, "radius"), // vec4, radius corners (top-left, top-right, bottom-left, bottom-right) - GetShaderLocation(rectangleShadowShader, "shadowRadius"), // float, shadow radius - GetShaderLocation(rectangleShadowShader, "shadowPower"), // float, shadow power - GetShaderLocation(rectangleShadowShader, "shadowOffset"), // vec2, shadow offset (NOTE: Y axis is flipped) - GetShaderLocation(rectangleShadowShader, "shadowScale"), // float, shadow scale - GetShaderLocation(rectangleShadowShader, "aaPower"), // float, anti-aliasing power - GetShaderLocation(rectangleShadowShader, "aaDistance") // float, anti-aliasing distance - }; - - // Load the rectangle border shader which will draw the rectangle's border - Shader rectangleBorderShader = LoadShader(TextFormat("resources/shaders/glsl%i/base.vs", GLSL_VERSION), - TextFormat("resources/shaders/glsl%i/rounded_rectangle_border.fs", GLSL_VERSION)); - - int rectangleBorderShaderLocs[5] = { - GetShaderLocation(rectangleBorderShader, "rectangle"), // vec4, rectangle bounds (x, y, width, height) - GetShaderLocation(rectangleBorderShader, "radius"), // vec4, radius corners (top-left, top-right, bottom-left, bottom-right) - GetShaderLocation(rectangleBorderShader, "borderThickness"), // float, border thickness - GetShaderLocation(rectangleBorderShader, "aaPower"), // float, anti-aliasing power - GetShaderLocation(rectangleBorderShader, "aaDistance") // float, anti-aliasing distance - }; - //-------------------------------------------------------------------------------------- + // Load the shader + Shader shader = LoadShader(TextFormat("resources/shaders/glsl%i/base.vs", GLSL_VERSION), + TextFormat("resources/shaders/glsl%i/rounded_rectangle.fs", GLSL_VERSION)); - // Set parameters - //-------------------------------------------------------------------------------------- - // Set 4 radius values for the rounded corners in pixels (top-left, top-right, bottom-left, bottom-right) - SetShaderValue(rectangleShader, rectangleShaderLocs[1], (float[]){ 5.0f, 10.0f, 15.0f, 20.0f }, SHADER_UNIFORM_VEC4); - SetShaderValue(rectangleShadowShader, rectangleShadowShaderLocs[1], (float[]){ 5.0f, 10.0f, 15.0f, 20.0f }, SHADER_UNIFORM_VEC4); - SetShaderValue(rectangleBorderShader, rectangleBorderShaderLocs[1], (float[]){ 5.0f, 10.0f, 15.0f, 20.0f }, SHADER_UNIFORM_VEC4); - - // Set shadow parameters (in pixels) - SetShaderValue(rectangleShadowShader, rectangleShadowShaderLocs[2], (float[]){ 20.0f }, SHADER_UNIFORM_FLOAT); // Shadow radius - SetShaderValue(rectangleShadowShader, rectangleShadowShaderLocs[3], (float[]){ 1.5f }, SHADER_UNIFORM_FLOAT); // Shadow power - SetShaderValue(rectangleShadowShader, rectangleShadowShaderLocs[4], (float[]){ 0.0f, -5.0f }, SHADER_UNIFORM_VEC2); // Shadow offset - SetShaderValue(rectangleShadowShader, rectangleShadowShaderLocs[5], (float[]){ 0.95f }, SHADER_UNIFORM_FLOAT); // Shadow scale - - // Set border parameters (in pixels) - SetShaderValue(rectangleBorderShader, rectangleBorderShaderLocs[2], (float[]){ 5.0f }, SHADER_UNIFORM_FLOAT); // Border thickness - - // Set anti-aliasing (power and distance) parameters for all shaders - SetShaderValue(rectangleShader, rectangleShaderLocs[2], (float[]){ 1.5f }, SHADER_UNIFORM_FLOAT); - SetShaderValue(rectangleShader, rectangleShaderLocs[3], (float[]){ 1.0f }, SHADER_UNIFORM_FLOAT); - SetShaderValue(rectangleShadowShader, rectangleShadowShaderLocs[6], (float[]){ 1.5f }, SHADER_UNIFORM_FLOAT); - SetShaderValue(rectangleShadowShader, rectangleShadowShaderLocs[7], (float[]){ 1.0f }, SHADER_UNIFORM_FLOAT); - SetShaderValue(rectangleBorderShader, rectangleBorderShaderLocs[3], (float[]){ 1.5f }, SHADER_UNIFORM_FLOAT); - SetShaderValue(rectangleBorderShader, rectangleBorderShaderLocs[4], (float[]){ 1.0f }, SHADER_UNIFORM_FLOAT); + // Create a rounded rectangle + RoundedRectangle roundedRectangle = CreateRoundedRectangle( + (Vector4){ 5.0f, 10.0f, 15.0f, 20.0f }, // Corner radius + 20.0f, // Shadow radius + (Vector2){ 0.0f, -5.0f }, // Shadow offset + 0.95f, // Shadow scale + 5.0f, // Border thickness + shader // Shader + ); - //-------------------------------------------------------------------------------------- + // Update shader uniforms + UpdateRoundedRectangle(roundedRectangle, shader); SetTargetFPS(60); //-------------------------------------------------------------------------------------- @@ -116,78 +106,82 @@ int main(void) ClearBackground(RAYWHITE); - // NOTE: Draw rectangle's shadow first using shader - DrawRectangleLines(30, 50, 150, 100, DARKGRAY); - DrawText("Rectangle shadow shader", 30, 35, 10, DARKGRAY); - + // Draw rectangle box with rounded corners using shader Rectangle rec = { 50, 70, 110, 60 }; + DrawRectangleLines(rec.x - 20, rec.y - 20, rec.width + 40, rec.height + 40, DARKGRAY); + DrawText("Rounded rectangle", rec.x - 20, rec.y - 35, 10, DARKGRAY); // Flip Y axis to match shader coordinate system - rec.y = GetScreenHeight() - rec.y - rec.height; + rec.y = screenHeight - rec.y - rec.height; + SetShaderValue(shader, roundedRectangle.rectangleLoc, (float[]){ rec.x, rec.y, rec.width, rec.height }, SHADER_UNIFORM_VEC4); - SetShaderValue(rectangleShadowShader, rectangleShadowShaderLocs[0], (float[]){ rec.x, rec.y, rec.width, rec.height }, SHADER_UNIFORM_VEC4); + // Only rectangle color + SetShaderValue(shader, roundedRectangle.colorLoc, (float[]) { rectangleColor.r/255.0f, rectangleColor.g/255.0f, rectangleColor.b/255.0f, rectangleColor.a/255.0f }, SHADER_UNIFORM_VEC4); + SetShaderValue(shader, roundedRectangle.shadowColorLoc, (float[]) { 0.0f, 0.0f, 0.0f, 0.0f }, SHADER_UNIFORM_VEC4); + SetShaderValue(shader, roundedRectangle.borderColorLoc, (float[]) { 0.0f, 0.0f, 0.0f, 0.0f }, SHADER_UNIFORM_VEC4); - BeginShaderMode(rectangleShadowShader); - DrawRectangle(0, 0, GetScreenWidth(), GetScreenHeight(), DARKBLUE); + BeginShaderMode(shader); + DrawRectangle(0, 0, screenWidth, screenHeight, WHITE); EndShaderMode(); - // Draw rectangle box with rounded corners using shader - DrawRectangleLines(30, 180, 150, 100, DARKGRAY); - DrawText("Rounded rectangle shader", 30, 165, 10, DARKGRAY); + + // Draw rectangle shadow using shader rec = (Rectangle){ 50, 200, 110, 60 }; - rec.y = GetScreenHeight() - rec.y - rec.height; + DrawRectangleLines(rec.x - 20, rec.y - 20, rec.width + 40, rec.height + 40, DARKGRAY); + DrawText("Rounded rectangle shadow", rec.x - 20, rec.y - 35, 10, DARKGRAY); - SetShaderValue(rectangleShader, rectangleShaderLocs[0], (float[]){ rec.x, rec.y, rec.width, rec.height }, SHADER_UNIFORM_VEC4); + rec.y = screenHeight - rec.y - rec.height; + SetShaderValue(shader, roundedRectangle.rectangleLoc, (float[]){ rec.x, rec.y, rec.width, rec.height }, SHADER_UNIFORM_VEC4); - BeginShaderMode(rectangleShader); - DrawRectangle(0, 0, GetScreenWidth(), GetScreenHeight(), BLUE); + // Only shadow color + SetShaderValue(shader, roundedRectangle.colorLoc, (float[]) { 0.0f, 0.0f, 0.0f, 0.0f }, SHADER_UNIFORM_VEC4); + SetShaderValue(shader, roundedRectangle.shadowColorLoc, (float[]) { shadowColor.r/255.0f, shadowColor.g/255.0f, shadowColor.b/255.0f, shadowColor.a/255.0f }, SHADER_UNIFORM_VEC4); + SetShaderValue(shader, roundedRectangle.borderColorLoc, (float[]) { 0.0f, 0.0f, 0.0f, 0.0f }, SHADER_UNIFORM_VEC4); + + BeginShaderMode(shader); + DrawRectangle(0, 0, screenWidth, screenHeight, WHITE); EndShaderMode(); - // Draw rectangle's border using shader - DrawRectangleLines(30, 310, 150, 100, DARKGRAY); - DrawText("Rectangle border shader", 30, 295, 10, DARKGRAY); + + // Draw rectangle's border using shader rec = (Rectangle){ 50, 330, 110, 60 }; - rec.y = GetScreenHeight() - rec.y - rec.height; + DrawRectangleLines(rec.x - 20, rec.y - 20, rec.width + 40, rec.height + 40, DARKGRAY); + DrawText("Rounded rectangle border", rec.x - 20, rec.y - 35, 10, DARKGRAY); - SetShaderValue(rectangleBorderShader, rectangleBorderShaderLocs[0], (float[]){ rec.x, rec.y, rec.width, rec.height }, SHADER_UNIFORM_VEC4); + rec.y = screenHeight - rec.y - rec.height; + SetShaderValue(shader, roundedRectangle.rectangleLoc, (float[]){ rec.x, rec.y, rec.width, rec.height }, SHADER_UNIFORM_VEC4); - BeginShaderMode(rectangleBorderShader); - DrawRectangle(0, 0, GetScreenWidth(), GetScreenHeight(), SKYBLUE); - EndShaderMode(); + // Only border color + SetShaderValue(shader, roundedRectangle.colorLoc, (float[]) { 0.0f, 0.0f, 0.0f, 0.0f }, SHADER_UNIFORM_VEC4); + SetShaderValue(shader, roundedRectangle.shadowColorLoc, (float[]) { 0.0f, 0.0f, 0.0f, 0.0f }, SHADER_UNIFORM_VEC4); + SetShaderValue(shader, roundedRectangle.borderColorLoc, (float[]) { borderColor.r/255.0f, borderColor.g/255.0f, borderColor.b/255.0f, borderColor.a/255.0f }, SHADER_UNIFORM_VEC4); - // Draw one more rectangle with all three combined - //-------------------------------------------------------------------------------------------------- - DrawRectangleLines(210, 50, 560, 360, DARKGRAY); - DrawText("Rectangle all three combined", 210, 35, 10, DARKGRAY); - - rec = (Rectangle){ 240, 80, 500, 300 }; - rec.y = GetScreenHeight() - rec.y - rec.height; + BeginShaderMode(shader); + DrawRectangle(0, 0, screenWidth, screenHeight, WHITE); + EndShaderMode(); - // Draw shadow - SetShaderValue(rectangleShadowShader, rectangleShadowShaderLocs[0], (float[]){ rec.x, rec.y, rec.width, rec.height }, SHADER_UNIFORM_VEC4); - BeginShaderMode(rectangleShadowShader); - DrawRectangle(0, 0, GetScreenWidth(), GetScreenHeight(), DARKBLUE); - EndShaderMode(); - // Draw rectangle - SetShaderValue(rectangleShader, rectangleShaderLocs[0], (float[]){ rec.x, rec.y, rec.width, rec.height }, SHADER_UNIFORM_VEC4); + // Draw one more rectangle with all three colors + rec = (Rectangle){ 240, 80, 500, 300 }; + DrawRectangleLines(rec.x - 30, rec.y - 30, rec.width + 60, rec.height + 60, DARKGRAY); + DrawText("Rectangle with all three combined", rec.x - 30, rec.y - 45, 10, DARKGRAY); - BeginShaderMode(rectangleShader); - DrawRectangle(0, 0, GetScreenWidth(), GetScreenHeight(), BLUE); - EndShaderMode(); + rec.y = screenHeight - rec.y - rec.height; + SetShaderValue(shader, roundedRectangle.rectangleLoc, (float[]){ rec.x, rec.y, rec.width, rec.height }, SHADER_UNIFORM_VEC4); - // Draw border - SetShaderValue(rectangleBorderShader, rectangleBorderShaderLocs[0], (float[]){ rec.x, rec.y, rec.width, rec.height }, SHADER_UNIFORM_VEC4); + // All three colors + SetShaderValue(shader, roundedRectangle.colorLoc, (float[]) { rectangleColor.r/255.0f, rectangleColor.g/255.0f, rectangleColor.b/255.0f, rectangleColor.a/255.0f }, SHADER_UNIFORM_VEC4); + SetShaderValue(shader, roundedRectangle.shadowColorLoc, (float[]) { shadowColor.r/255.0f, shadowColor.g/255.0f, shadowColor.b/255.0f, shadowColor.a/255.0f }, SHADER_UNIFORM_VEC4); + SetShaderValue(shader, roundedRectangle.borderColorLoc, (float[]) { borderColor.r/255.0f, borderColor.g/255.0f, borderColor.b/255.0f, borderColor.a/255.0f }, SHADER_UNIFORM_VEC4); - BeginShaderMode(rectangleBorderShader); - DrawRectangle(0, 0, GetScreenWidth(), GetScreenHeight(), SKYBLUE); + BeginShaderMode(shader); + DrawRectangle(0, 0, screenWidth, screenHeight, WHITE); EndShaderMode(); - //-------------------------------------------------------------------------------------------------- - DrawText("(c) Rounded rectangle SDF by Iñigo Quilez. MIT License.", GetScreenWidth() - 300, GetScreenHeight() - 20, 10, BLACK); + DrawText("(c) Rounded rectangle SDF by Iñigo Quilez. MIT License.", screenWidth - 300, screenHeight - 20, 10, BLACK); EndDrawing(); //---------------------------------------------------------------------------------- @@ -195,14 +189,50 @@ int main(void) // De-Initialization //-------------------------------------------------------------------------------------- - - // Unload shader - UnloadShader(rectangleShader); - UnloadShader(rectangleShadowShader); - UnloadShader(rectangleBorderShader); + UnloadShader(shader); // Unload shader CloseWindow(); // Close window and OpenGL context //-------------------------------------------------------------------------------------- return 0; -} \ No newline at end of file +} + +//------------------------------------------------------------------------------------ +// Module Functions Definitions +//------------------------------------------------------------------------------------ + +// Create a rounded rectangle and set uniform locations +RoundedRectangle CreateRoundedRectangle(Vector4 cornerRadius, float shadowRadius, Vector2 shadowOffset, float shadowScale, float borderThickness, Shader shader) +{ + RoundedRectangle rec; + rec.cornerRadius = cornerRadius; + rec.shadowRadius = shadowRadius; + rec.shadowOffset = shadowOffset; + rec.shadowScale = shadowScale; + rec.borderThickness = borderThickness; + + // Get shader uniform locations + rec.rectangleLoc = GetShaderLocation(shader, "rectangle"); + rec.radiusLoc = GetShaderLocation(shader, "radius"); + rec.colorLoc = GetShaderLocation(shader, "color"); + rec.shadowRadiusLoc = GetShaderLocation(shader, "shadowRadius"); + rec.shadowOffsetLoc = GetShaderLocation(shader, "shadowOffset"); + rec.shadowScaleLoc = GetShaderLocation(shader, "shadowScale"); + rec.shadowColorLoc = GetShaderLocation(shader, "shadowColor"); + rec.borderThicknessLoc = GetShaderLocation(shader, "borderThickness"); + rec.borderColorLoc = GetShaderLocation(shader, "borderColor"); + + UpdateRoundedRectangle(rec, shader); + + return rec; +} + +// Update rounded rectangle uniforms +void UpdateRoundedRectangle(RoundedRectangle rec, Shader shader) +{ + SetShaderValue(shader, rec.radiusLoc, (float[]){ rec.cornerRadius.x, rec.cornerRadius.y, rec.cornerRadius.z, rec.cornerRadius.w }, SHADER_UNIFORM_VEC4); + SetShaderValue(shader, rec.shadowRadiusLoc, &rec.shadowRadius, SHADER_UNIFORM_FLOAT); + SetShaderValue(shader, rec.shadowOffsetLoc, (float[]){ rec.shadowOffset.x, rec.shadowOffset.y }, SHADER_UNIFORM_VEC2); + SetShaderValue(shader, rec.shadowScaleLoc, &rec.shadowScale, SHADER_UNIFORM_FLOAT); + SetShaderValue(shader, rec.borderThicknessLoc, &rec.borderThickness, SHADER_UNIFORM_FLOAT); +}