diff --git a/build.zig b/build.zig index 0799d55..2aeaaf6 100755 --- a/build.zig +++ b/build.zig @@ -50,6 +50,11 @@ pub fn build(b: *Builder) void { .path = "examples/core/2d_camera.zig", .desc = "Shows the functionality of a 2D camera", }, + .{ + .name = "texture_outline", + .path = "examples/shaders/texture_outline.zig", + .desc = "Uses a shader to create an outline around a sprite", + }, // .{ // .name = "models_loading", // .path = "examples/models/models_loading.zig", diff --git a/examples/shaders/texture_outline.zig b/examples/shaders/texture_outline.zig new file mode 100644 index 0000000..26ece52 --- /dev/null +++ b/examples/shaders/texture_outline.zig @@ -0,0 +1,80 @@ +// A raylib port of https://github.com/raysan5/raylib/blob/master/examples/shaders/shaders_texture_outline.c + + +const rl = @import("raylib"); +const std = @import("std"); + +//------------------------------------------------------------------------------------ +// Program main entry point +//------------------------------------------------------------------------------------ +pub fn main() anyerror!void { + // Initialization + //-------------------------------------------------------------------------------------- + const screenWidth = 800; + const screenHeight = 450; + + rl.InitWindow(screenWidth, screenHeight, "raylib [shaders] example - Apply an outline to a texture"); + + const texture: rl.Texture2D = rl.LoadTexture("resources/textures/fudesumi.png"); + + const shdrOutline: rl.Shader = rl.LoadShader(0, rl.TextFormat("resources/shaders/glsl330/outline.fs", @intCast(c_int, 330))); + + var outlineSize: f32 = 2.0; + const outlineColor = [4]f32{ 1.0, 0.0, 0.0, 1.0 }; // Normalized RED color + const textureSize = rl.Vector2{ .x=@intToFloat(f32, texture.width), .y=@intToFloat(f32,texture.height) }; + + // Get shader locations + const outlineSizeLoc = rl.GetShaderLocation(shdrOutline, "outlineSize"); + const outlineColorLoc = rl.GetShaderLocation(shdrOutline, "outlineColor"); + const textureSizeLoc = rl.GetShaderLocation(shdrOutline, "textureSize"); + + // Set shader values (they can be changed later) + rl.SetShaderValue(shdrOutline, outlineSizeLoc, &outlineSize, @enumToInt(rl.ShaderUniformDataType.SHADER_UNIFORM_FLOAT)); + rl.SetShaderValue(shdrOutline, outlineColorLoc, &outlineColor, @enumToInt(rl.ShaderUniformDataType.SHADER_UNIFORM_VEC4)); + rl.SetShaderValue(shdrOutline, textureSizeLoc, &textureSize, @enumToInt(rl.ShaderUniformDataType.SHADER_UNIFORM_VEC2)); + + rl.SetTargetFPS(60); // Set our game to run at 60 frames-per-second + //-------------------------------------------------------------------------------------- + + // Main game loop + while (!rl.WindowShouldClose()) // Detect window close button or ESC key + { + // Update + //---------------------------------------------------------------------------------- + outlineSize += rl.GetMouseWheelMove(); + if (outlineSize < 1.0) outlineSize = 1.0; + + rl.SetShaderValue(shdrOutline, outlineSizeLoc, &outlineSize, @enumToInt(rl.ShaderUniformDataType.SHADER_UNIFORM_FLOAT)); + //---------------------------------------------------------------------------------- + + // Draw + //---------------------------------------------------------------------------------- + rl.BeginDrawing(); + + rl.ClearBackground(rl.RAYWHITE); + + rl.BeginShaderMode(shdrOutline); + + rl.DrawTexture(texture, @divFloor(rl.GetScreenWidth(),2) - @divFloor(texture.width,2), -30, rl.WHITE); + + rl.EndShaderMode(); + + rl.DrawText("Shader-based\ntexture\noutline", 10, 10, 20, rl.GRAY); + + rl.DrawText(rl.TextFormat("Outline size: %i px", @floatToInt(i32, outlineSize)), 10, 120, 20, rl.MAROON); + + rl.DrawFPS(710, 10); + + rl.EndDrawing(); + //---------------------------------------------------------------------------------- + } + + // De-Initialization + //-------------------------------------------------------------------------------------- + rl.UnloadTexture(texture); + rl.UnloadShader(shdrOutline); + + rl.CloseWindow(); // Close window and OpenGL context + //-------------------------------------------------------------------------------------- + +} \ No newline at end of file diff --git a/resources/shaders/glsl330/outline.fs b/resources/shaders/glsl330/outline.fs new file mode 100644 index 0000000..2584a21 --- /dev/null +++ b/resources/shaders/glsl330/outline.fs @@ -0,0 +1,35 @@ +#version 330 + +// Input vertex attributes (from vertex shader) +in vec2 fragTexCoord; +in vec4 fragColor; + +// Input uniform values +uniform sampler2D texture0; +uniform vec4 colDiffuse; + +uniform vec2 textureSize; +uniform float outlineSize; +uniform vec4 outlineColor; + +// Output fragment color +out vec4 finalColor; + +void main() +{ + vec4 texel = texture(texture0, fragTexCoord); // Get texel color + vec2 texelScale = vec2(0.0); + texelScale.x = outlineSize/textureSize.x; + texelScale.y = outlineSize/textureSize.y; + + // We sample four corner texels, but only for the alpha channel (this is for the outline) + vec4 corners = vec4(0.0); + corners.x = texture(texture0, fragTexCoord + vec2(texelScale.x, texelScale.y)).a; + corners.y = texture(texture0, fragTexCoord + vec2(texelScale.x, -texelScale.y)).a; + corners.z = texture(texture0, fragTexCoord + vec2(-texelScale.x, texelScale.y)).a; + corners.w = texture(texture0, fragTexCoord + vec2(-texelScale.x, -texelScale.y)).a; + + float outline = min(dot(corners, vec4(1.0)), 1.0); + vec4 color = mix(vec4(0.0), outlineColor, outline); + finalColor = mix(color, texel, texel.a); +} \ No newline at end of file diff --git a/resources/textures/fudesumi.png b/resources/textures/fudesumi.png new file mode 100644 index 0000000..c77c287 Binary files /dev/null and b/resources/textures/fudesumi.png differ