diff --git a/examples/Makefile b/examples/Makefile index 3ae76baff..ecd4344a6 100644 --- a/examples/Makefile +++ b/examples/Makefile @@ -456,7 +456,8 @@ SHADERS = \ shaders/shaders_eratosthenes \ shaders/shaders_basic_lighting \ shaders/shaders_fog \ - shaders/shaders_simple_mask + shaders/shaders_simple_mask \ + shaders/shaders_spotlight AUDIO = \ audio/audio_module_playing \ diff --git a/examples/shaders/resources/raysan.png b/examples/shaders/resources/raysan.png new file mode 100644 index 000000000..3d4e70fe4 Binary files /dev/null and b/examples/shaders/resources/raysan.png differ diff --git a/examples/shaders/resources/shaders/glsl100/spotlight.fs b/examples/shaders/resources/shaders/glsl100/spotlight.fs new file mode 100644 index 000000000..204b89a72 --- /dev/null +++ b/examples/shaders/resources/shaders/glsl100/spotlight.fs @@ -0,0 +1,52 @@ +#version 100 + +precision mediump float; + +#define MAX_SPOTS 4 +#define RADIUS 256.0 +#define INNER 200.0 + +// Inputs +// array of spotlight positions +uniform vec2 spots[MAX_SPOTS]; + +uniform float screenWidth; // width of the screen + +void main() +{ + + float alpha; + // get the position of the current fragment (screen coordinates!) + vec2 pos = vec2(gl_FragCoord.x, gl_FragCoord.y); + + + // find out which spotlight is nearest + float d = 65000.0; // some high value + float di = 0.0; + + for (int i = 0; i < MAX_SPOTS; i++) + { + di = distance(pos, spots[i]); + if (d > di) d = di; + } + + // d now equals distance to nearest spot... + if (d > RADIUS) { + alpha = 1.0; + } else { + if (d < INNER) { + alpha = 0.0; + } else { + alpha = (d - INNER) / (RADIUS - INNER); + } + } + + // right hand side of screen is dimly lit, could make the + // threshold value user definable. + if (pos.x > screenWidth/2.0 && alpha > 0.9) { + alpha = 0.9; + } + + // could make the black out colour user definable... + gl_FragColor = vec4( 0, 0, 0, alpha); +} diff --git a/examples/shaders/resources/shaders/glsl330/spotlight.fs b/examples/shaders/resources/shaders/glsl330/spotlight.fs new file mode 100644 index 000000000..f97722c6c --- /dev/null +++ b/examples/shaders/resources/shaders/glsl330/spotlight.fs @@ -0,0 +1,53 @@ +#version 330 + +// Output fragment color +out vec4 finalColor; + +#define MAX_SPOTS 4 +#define RADIUS 256 +#define INNER 200 + +// Inputs +// array of spotlight positions +uniform vec2 spots[MAX_SPOTS]; + +uniform float screenWidth; // width of the screen + +void main() +{ + + float alpha; + // get the position of the current fragment (screen coordinates!) + vec2 pos = vec2(gl_FragCoord.x, gl_FragCoord.y); + + + // find out which spotlight is nearest + float d = 65000; // some high value + float di = 0; + + for (int i = 0; i < MAX_SPOTS; i++) + { + di = distance(pos, spots[i]); + if (d > di) d = di; + } + + // d now equals distance to nearest spot... + if (d > RADIUS) { + alpha = 1.0; + } else { + if (d < INNER) { + alpha = 0.0; + } else { + alpha = (d - INNER) / (RADIUS - INNER); + } + } + + // right hand side of screen is dimly lit, could make the + // threshold value user definable. + if (pos.x>screenWidth/2.0 && alpha >0.9) { + alpha = 0.9; + } + + // could make the black out colour user definable... + finalColor = vec4( 0, 0, 0, alpha); +} diff --git a/examples/shaders/shaders_spotlight.c b/examples/shaders/shaders_spotlight.c new file mode 100644 index 000000000..ccd91fdcc --- /dev/null +++ b/examples/shaders/shaders_spotlight.c @@ -0,0 +1,225 @@ +/* + * Copyright (c) 2019 Chris Camacho (codifies - http://bedroomcoders.co.uk/) + * + * 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. + * + */ + +/* The shader makes alpha holes in the forground to give the apearance of a top + * down look at a spotlight casting a pool of light... + * + * The right hand side of the screen there is just enough light to see whats + * going on without the spot light, great for a stealth type game where you + * have to avoid the spotlights. + * + * The left hand side of the screen is in pitch dark except for where the spotlights + * are. + * + * Although this example doesn't scale like the letterbox example, you could integrate + * the two techniques, but by scaling the actual colour of the render texture rather + * than using alpha as a mask. + */ + +#include +#include + +#include "raylib.h" +#include "raymath.h" + +#if defined(PLATFORM_DESKTOP) + #define GLSL_VERSION 330 +#else // PLATFORM_RPI, PLATFORM_ANDROID, PLATFORM_WEB + #define GLSL_VERSION 100 +#endif + +// single digit only! +#define MAXSPOT 4 + +#define numStars 400 + +#define screenWidth 1280 +#define screenHeight 720 + +// the stars in the star field have a position and velocity +typedef struct star { + Vector2 pos; + Vector2 vel; +} star; + + +void updateStar(star *s); +void resetStar(star *s); + +int main(void) +{ + // Initialization + //-------------------------------------------------------------------------------------- + star stars[numStars]; + + for (int n=0; n < numStars; n++) { + resetStar(&stars[n]); + } + + // progress all the stars on, so they don't all start in the centre + for (int m=0; m < screenWidth / 2.0; m++) { + for (int n=0; n screenWidth-128) spotVel[i].x = -spotVel[i].x; + if (spotPos[i].y < 128) spotVel[i].y = -spotVel[i].y; + if (spotPos[i].y > screenHeight-128) spotVel[i].y = -spotVel[i].y; + + SetShaderValue(spotShader, spotLoc[i], &spotPos[i].x, UNIFORM_VEC2); + } + + // Draw + //---------------------------------------------------------------------------------- + BeginDrawing(); + + ClearBackground((Color){0,32,128,255}); + + // stars and bobs + for (int n=0; n1)); + (*s).pos = Vector2Add( (*s).pos, + Vector2MultiplyV((*s).vel,(Vector2){8,8} )); +} + +void updateStar(star *s) +{ + (*s).pos = Vector2Add((*s).pos, (*s).vel); + if ((*s).pos.x < 0 || (*s).pos.x > screenWidth || + (*s).pos.y < 0 || (*s).pos.y > screenHeight) { + resetStar(s); + } +} + +