├── .gitignore ├── img └── preview.png ├── CrtTextBox ├── Assets │ ├── Fonts │ │ └── VGA │ │ │ ├── PxPlus_IBM_VGA8.ttf │ │ │ └── LICENSE.TXT │ └── crt.sksl ├── CrtTextBox.sln.DotSettings ├── App.axaml ├── CrtTextBox.sln ├── app.manifest ├── App.axaml.cs ├── Skins │ ├── SimpleSkin.cs │ ├── RetroGreenDos.cs │ ├── RetroMonoDos.cs │ ├── RetroPlasma.cs │ └── SkinBase.cs ├── Program.cs ├── CrtTextBox.csproj ├── MainWindow.axaml ├── MainWindow.axaml.cs └── ShaderControl.cs ├── LICENSE └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | */bin/ 2 | */obj/ 3 | */.*/ 4 | */_*/ 5 | -------------------------------------------------------------------------------- /img/preview.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/deanthecoder/CrtTextBox/HEAD/img/preview.png -------------------------------------------------------------------------------- /CrtTextBox/Assets/Fonts/VGA/PxPlus_IBM_VGA8.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/deanthecoder/CrtTextBox/HEAD/CrtTextBox/Assets/Fonts/VGA/PxPlus_IBM_VGA8.ttf -------------------------------------------------------------------------------- /CrtTextBox/CrtTextBox.sln.DotSettings: -------------------------------------------------------------------------------- 1 | 2 | True -------------------------------------------------------------------------------- /CrtTextBox/App.axaml: -------------------------------------------------------------------------------- 1 | 5 | 6 | 7 | 8 | 9 | 10 | avares://CrtTextBox/Assets/Fonts/VGA#PxPlus IBM VGA8 11 | 12 | -------------------------------------------------------------------------------- /CrtTextBox/CrtTextBox.sln: -------------------------------------------------------------------------------- 1 | 2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CrtTextBox", "CrtTextBox.csproj", "{428C3EE5-5D90-4C7A-A46C-4F7B43F563FD}" 4 | EndProject 5 | Global 6 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 7 | Debug|Any CPU = Debug|Any CPU 8 | Release|Any CPU = Release|Any CPU 9 | EndGlobalSection 10 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 11 | {428C3EE5-5D90-4C7A-A46C-4F7B43F563FD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 12 | {428C3EE5-5D90-4C7A-A46C-4F7B43F563FD}.Debug|Any CPU.Build.0 = Debug|Any CPU 13 | {428C3EE5-5D90-4C7A-A46C-4F7B43F563FD}.Release|Any CPU.ActiveCfg = Release|Any CPU 14 | {428C3EE5-5D90-4C7A-A46C-4F7B43F563FD}.Release|Any CPU.Build.0 = Release|Any CPU 15 | EndGlobalSection 16 | EndGlobal 17 | -------------------------------------------------------------------------------- /CrtTextBox/app.manifest: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | 7 | 8 | 9 | 10 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /CrtTextBox/App.axaml.cs: -------------------------------------------------------------------------------- 1 | // Code authored by Dean Edis (DeanTheCoder). 2 | // Anyone is free to copy, modify, use, compile, or distribute this software, 3 | // either in source code form or as a compiled binary, for any non-commercial 4 | // purpose. 5 | // 6 | // If you modify the code, please retain this copyright header, 7 | // and consider contributing back to the repository or letting us know 8 | // about your modifications. Your contributions are valued! 9 | // 10 | // THE SOFTWARE IS PROVIDED AS IS, WITHOUT WARRANTY OF ANY KIND. 11 | using Avalonia; 12 | using Avalonia.Controls.ApplicationLifetimes; 13 | using Avalonia.Markup.Xaml; 14 | 15 | namespace RenderTest; 16 | 17 | public class App : Application 18 | { 19 | public override void Initialize() 20 | { 21 | AvaloniaXamlLoader.Load(this); 22 | } 23 | 24 | public override void OnFrameworkInitializationCompleted() 25 | { 26 | if (ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop) 27 | desktop.MainWindow = new MainWindow(); 28 | 29 | base.OnFrameworkInitializationCompleted(); 30 | } 31 | } -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2024 Dean Edis 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /CrtTextBox/Skins/SimpleSkin.cs: -------------------------------------------------------------------------------- 1 | // // Code authored by Dean Edis (DeanTheCoder). 2 | // // Anyone is free to copy, modify, use, compile, or distribute this software, 3 | // // either in source code form or as a compiled binary, for any non-commercial 4 | // // purpose. 5 | // // 6 | // // If you modify the code, please retain this copyright header, 7 | // // and consider contributing back to the repository or letting us know 8 | // // about your modifications. Your contributions are valued! 9 | // // 10 | // // THE SOFTWARE IS PROVIDED AS IS, WITHOUT WARRANTY OF ANY KIND. 11 | namespace RenderTest.Skins; 12 | 13 | public class SimpleSkin : SkinBase 14 | { 15 | // Font properties 16 | public override string ForegroundColor => "#e0e000"; 17 | public override string BackgroundColor => "#000080"; 18 | public override string SelectionColor => "#004080"; 19 | public override double FontSize => 16.0; 20 | public override double BrightnessBoost => 1.0; 21 | 22 | // Shader uniform properties 23 | public override bool EnableScanlines => false; 24 | public override bool EnableSurround => false; 25 | public override bool EnableSignalDistortion => false; 26 | public override bool EnableShadows => false; 27 | } -------------------------------------------------------------------------------- /CrtTextBox/Program.cs: -------------------------------------------------------------------------------- 1 | // Code authored by Dean Edis (DeanTheCoder). 2 | // Anyone is free to copy, modify, use, compile, or distribute this software, 3 | // either in source code form or as a compiled binary, for any non-commercial 4 | // purpose. 5 | // 6 | // If you modify the code, please retain this copyright header, 7 | // and consider contributing back to the repository or letting us know 8 | // about your modifications. Your contributions are valued! 9 | // 10 | // THE SOFTWARE IS PROVIDED AS IS, WITHOUT WARRANTY OF ANY KIND. 11 | using System; 12 | using Avalonia; 13 | 14 | namespace RenderTest; 15 | 16 | static class Program 17 | { 18 | // Initialization code. Don't use any Avalonia, third-party APIs or any 19 | // SynchronizationContext-reliant code before AppMain is called: things aren't initialized 20 | // yet and stuff might break. 21 | [STAThread] 22 | public static void Main(string[] args) 23 | { 24 | BuildAvaloniaApp() 25 | .StartWithClassicDesktopLifetime(args); 26 | } 27 | 28 | // Avalonia configuration, don't remove; also used by visual designer. 29 | public static AppBuilder BuildAvaloniaApp() 30 | { 31 | return AppBuilder.Configure() 32 | .UsePlatformDetect() 33 | .WithInterFont() 34 | .LogToTrace(); 35 | } 36 | } -------------------------------------------------------------------------------- /CrtTextBox/Skins/RetroGreenDos.cs: -------------------------------------------------------------------------------- 1 | // // Code authored by Dean Edis (DeanTheCoder). 2 | // // Anyone is free to copy, modify, use, compile, or distribute this software, 3 | // // either in source code form or as a compiled binary, for any non-commercial 4 | // // purpose. 5 | // // 6 | // // If you modify the code, please retain this copyright header, 7 | // // and consider contributing back to the repository or letting us know 8 | // // about your modifications. Your contributions are valued! 9 | // // 10 | // // THE SOFTWARE IS PROVIDED AS IS, WITHOUT WARRANTY OF ANY KIND. 11 | namespace RenderTest.Skins; 12 | 13 | public class RetroGreenDos : SkinBase 14 | { 15 | // Font properties 16 | public override string ForegroundColor => "#40ff40"; 17 | public override string BackgroundColor => "#082008"; 18 | public override string SelectionColor => "#207020"; 19 | public override double FontSize => 16.0; // Font size 16.0 20 | public override double BrightnessBoost => 1.1; 21 | 22 | // Shader uniform properties 23 | public override bool EnableScanlines => true; // Enable scanlines 24 | public override bool EnableSurround => true; // Enable CRT surround effect 25 | public override bool EnableSignalDistortion => true; // Enable signal distortion 26 | public override bool EnableShadows => true; // Enable shadows 27 | } -------------------------------------------------------------------------------- /CrtTextBox/Skins/RetroMonoDos.cs: -------------------------------------------------------------------------------- 1 | // // Code authored by Dean Edis (DeanTheCoder). 2 | // // Anyone is free to copy, modify, use, compile, or distribute this software, 3 | // // either in source code form or as a compiled binary, for any non-commercial 4 | // // purpose. 5 | // // 6 | // // If you modify the code, please retain this copyright header, 7 | // // and consider contributing back to the repository or letting us know 8 | // // about your modifications. Your contributions are valued! 9 | // // 10 | // // THE SOFTWARE IS PROVIDED AS IS, WITHOUT WARRANTY OF ANY KIND. 11 | namespace RenderTest.Skins; 12 | 13 | public class RetroMonoDos : SkinBase 14 | { 15 | // Font properties 16 | public override string ForegroundColor => "#ffffff"; 17 | public override string BackgroundColor => "#202020"; 18 | public override string SelectionColor => "#505050"; 19 | public override double FontSize => 16.0; // Font size 16.0 20 | public override double BrightnessBoost => 1.0; 21 | 22 | // Shader uniform properties 23 | public override bool EnableScanlines => true; // Enable scanlines 24 | public override bool EnableSurround => true; // Enable CRT surround effect 25 | public override bool EnableSignalDistortion => true; // Enable signal distortion 26 | public override bool EnableShadows => true; // Enable shadows 27 | } -------------------------------------------------------------------------------- /CrtTextBox/Skins/RetroPlasma.cs: -------------------------------------------------------------------------------- 1 | // Code authored by Dean Edis (DeanTheCoder). 2 | // Anyone is free to copy, modify, use, compile, or distribute this software, 3 | // either in source code form or as a compiled binary, for any non-commercial 4 | // purpose. 5 | // 6 | // If you modify the code, please retain this copyright header, 7 | // and consider contributing back to the repository or letting us know 8 | // about your modifications. Your contributions are valued! 9 | // 10 | // THE SOFTWARE IS PROVIDED AS IS, WITHOUT WARRANTY OF ANY KIND. 11 | 12 | namespace RenderTest.Skins; 13 | 14 | public class RetroPlasma : SkinBase 15 | { 16 | // Font properties 17 | public override string ForegroundColor => "#ffa000"; // Orange foreground 18 | public override string BackgroundColor => "#402000"; // Brownish-orange background 19 | public override string SelectionColor => "#804000"; // Halfway color for selection 20 | public override double FontSize => 16.0; // Font size 16.0 21 | public override double BrightnessBoost => 1.2; 22 | 23 | // Shader uniform properties 24 | public override bool EnableScanlines => true; // Enable scanlines 25 | public override bool EnableSurround => true; // Enable CRT surround effect 26 | public override bool EnableSignalDistortion => true; // Enable signal distortion 27 | public override bool EnableShadows => true; // Enable shadows 28 | } -------------------------------------------------------------------------------- /CrtTextBox/Skins/SkinBase.cs: -------------------------------------------------------------------------------- 1 | // Code authored by Dean Edis (DeanTheCoder). 2 | // Anyone is free to copy, modify, use, compile, or distribute this software, 3 | // either in source code form or as a compiled binary, for any non-commercial 4 | // purpose. 5 | // 6 | // If you modify the code, please retain this copyright header, 7 | // and consider contributing back to the repository or letting us know 8 | // about your modifications. Your contributions are valued! 9 | // 10 | // THE SOFTWARE IS PROVIDED AS IS, WITHOUT WARRANTY OF ANY KIND. 11 | 12 | namespace RenderTest.Skins; 13 | 14 | public abstract class SkinBase 15 | { 16 | // Font properties. 17 | public abstract string ForegroundColor { get; } // e.g., "#FFFFFF" for white text 18 | public abstract string BackgroundColor { get; } // e.g., "#000000" for black background 19 | public abstract string SelectionColor { get; } // e.g., "#FF0000" for red selection 20 | public abstract double FontSize { get; } // e.g., 16.0 21 | 22 | // Shader uniform properties 23 | public abstract double BrightnessBoost { get; } 24 | public abstract bool EnableScanlines { get; } // true to enable scanlines 25 | public abstract bool EnableSurround { get; } // true to enable CRT surround effect 26 | public abstract bool EnableSignalDistortion { get; } // true to enable signal distortion 27 | public abstract bool EnableShadows { get; } // true to enable shadows 28 | } -------------------------------------------------------------------------------- /CrtTextBox/CrtTextBox.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | WinExe 4 | net7.0 5 | disable 6 | true 7 | app.manifest 8 | true 9 | true 10 | RenderTest 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | -------------------------------------------------------------------------------- /CrtTextBox/MainWindow.axaml: -------------------------------------------------------------------------------- 1 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 27 | 28 | 35 | 36 | 37 | 38 | 39 | 40 | 45 | 46 | 47 | -------------------------------------------------------------------------------- /CrtTextBox/MainWindow.axaml.cs: -------------------------------------------------------------------------------- 1 | // Code authored by Dean Edis (DeanTheCoder). 2 | // Anyone is free to copy, modify, use, compile, or distribute this software, 3 | // either in source code form or as a compiled binary, for any non-commercial 4 | // purpose. 5 | // 6 | // If you modify the code, please retain this copyright header, 7 | // and consider contributing back to the repository or letting us know 8 | // about your modifications. Your contributions are valued! 9 | // 10 | // THE SOFTWARE IS PROVIDED AS IS, WITHOUT WARRANTY OF ANY KIND. 11 | using System; 12 | using System.IO; 13 | using Avalonia; 14 | using Avalonia.Controls; 15 | using Avalonia.Input; 16 | using Avalonia.Interactivity; 17 | using Avalonia.Media; 18 | using Avalonia.Platform; 19 | using RenderTest.Skins; 20 | 21 | namespace RenderTest; 22 | 23 | public partial class MainWindow : Window 24 | { 25 | public MainWindow() 26 | { 27 | InitializeComponent(); 28 | } 29 | 30 | private void OnTextBoxLoaded(object sender, RoutedEventArgs _) 31 | { 32 | var textBox = (TextBox)sender; 33 | textBox.ContextMenu = null; 34 | 35 | // Preload the text box with the shader code. 36 | using var skslStream = new StreamReader(AssetLoader.Open(new Uri("avares://CrtTextBox/Assets/crt.sksl"))); 37 | textBox.Text = skslStream.ReadToEnd(); 38 | textBox.Focus(); 39 | 40 | // Allow real-time SKSL updates using 'F5'. 41 | textBox.KeyDown += (_, args) => 42 | { 43 | if (args.PhysicalKey == PhysicalKey.F5) 44 | Shader.SetSksl(textBox.Text); 45 | }; 46 | 47 | // Configure the default CRT shader. 48 | ApplyRetroSkin(new RetroPlasma()); 49 | } 50 | 51 | private void ApplyRetroSkin(SkinBase skin) 52 | { 53 | // Apply font and color settings. 54 | Source.Foreground = SolidColorBrush.Parse(skin.ForegroundColor); 55 | Source.Background = SolidColorBrush.Parse(skin.BackgroundColor); 56 | Source.SelectionBrush = SolidColorBrush.Parse(skin.SelectionColor); 57 | Source.FontSize = skin.FontSize; 58 | 59 | // Set the focused background color in the resources. 60 | Source.Resources["TextControlBackgroundFocused"] = Source.Background; 61 | Source.Resources["TextControlBorderThemeThicknessFocused"] = new Thickness(0); 62 | 63 | // Configure the CRT shader using the provided skin. 64 | Shader.AddUniform("brightnessBoost", (float)skin.BrightnessBoost); 65 | Shader.AddUniform("enableScanlines", skin.EnableScanlines); 66 | Shader.AddUniform("enableSurround", skin.EnableSurround); 67 | Shader.AddUniform("enableSignalDistortion", skin.EnableSignalDistortion); 68 | Shader.AddUniform("enableShadows", skin.EnableShadows); 69 | 70 | // Alignment. 71 | MarginPanel.Margin = new Thickness(skin.EnableSurround ? 20 : 0); 72 | } 73 | 74 | private void OnShaderControlLoaded(object sender, RoutedEventArgs _) 75 | { 76 | // Set ShaderControl's source control. 77 | ((ShaderControl)sender).ControlSource = Source; 78 | } 79 | 80 | public void SetTheme(string name) 81 | { 82 | switch (name) 83 | { 84 | case "RetroPlasma": 85 | ApplyRetroSkin(new RetroPlasma()); 86 | return; 87 | case "RetroGreenDos": 88 | ApplyRetroSkin(new RetroGreenDos()); 89 | return; 90 | case "RetroMonoDos": 91 | ApplyRetroSkin(new RetroMonoDos()); 92 | return; 93 | case "SimpleSkin": 94 | ApplyRetroSkin(new SimpleSkin()); 95 | return; 96 | } 97 | } 98 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![Twitter Follow](https://img.shields.io/twitter/follow/deanthecoder?style=social)](https://twitter.com/deanthecoder) 2 | 3 | # CrtTextBox 4 | 5 | **CrtTextBox** is an Avalonia C# project that enhances a standard TextBox control with a custom SKSL shader, giving it the appearance of a retro CRT screen. This effect adds a nostalgic touch to your UI with features like fish-eye distortion, scan lines, vignette, screen jitter, background noise, and a scrolling electron bar. 6 | 7 | ![](img/preview.png) 8 | 9 | It makes use of a custom `ShaderControl` control, allowing any SKSL shader code to be applied to a source Avalonia UI control. 10 | The `CrtTextBox` example demonstrate how to use it with a `TextBox`, but any other source control can be used. 11 | 12 | ## Features 13 | 14 | - **Retro CRT Look**: The shader applies various effects to create a convincing retro CRT display, including: 15 | - Fish-eye distortion 16 | - Scan lines 17 | - Vignette effect 18 | - Screen jitter 19 | - Background noise 20 | - Scrolling electron bar 21 | - Monitor 'surround' with screen reflection 22 | 23 | - **Cross-Platform Compatibility**: Built with [Avalonia](https://avaloniaui.net/), ensuring compatibility across Windows, MacOS, and Linux. 24 | 25 | - **Customizable**: The shader can be easily integrated into any Avalonia application and modified to suit different visual styles. 26 | 27 | ## Getting Started 28 | 29 | ### Prerequisites 30 | 31 | - .NET compatible IDE such as [JetBrains Rider](https://www.jetbrains.com/rider/) or [Visual Studio 2022](https://visualstudio.microsoft.com/vs/). 32 | - Basic knowledge of C# and Avalonia UI. 33 | 34 | ### Building From Source 35 | 36 | 1. Clone the repository from GitHub. 37 | 2. Open the solution in your IDE. 38 | 3. Build and run the project. 39 | 40 | ### Using the Text Editor 41 | 42 | The main view is taken up with the shader code itself. Feel free to modify it and press `F5` to apply changes. Right-click outside of the text area to switch Themes. 43 | 44 | ### Create Your Own Theme 45 | 46 | Check out the `Themes` folder in the source tree. Modify the code to toggle features, or create your own theme from scratch. 47 | 48 | ### Using the `ShaderControl` 49 | 50 | The `ShaderControl` object is a standalone class and can be copied into your own project, and applied to any control with any shader code. 51 | 52 | 1. Add `ShaderControl` to your AXAML. 53 | 2. From the code-behind, set the `ControlSource` property to the UI control you wish to apply the shader to. 54 | 3. Set the `FPS` property, which determines the frequency the source control is sampled. 55 | 4. Set `ShaderUri` to point to the location of your SKSL shader code. Use `crt.sksl` as a reference. 56 | 57 | Custom `uniform` values can be passed into the shader code using `ShaderControl.AddUniform(name, value)`. 58 | 59 | ## Contribution and Improvements 60 | 61 | CrtTextBox is an open-source project, and contributions are welcome. If you have ideas for new features, improvements, or bug fixes, feel free to submit a pull request. Please note that this is a side project, so responses might not be immediate. 62 | 63 | ## Credits 64 | 65 | * Created with help from the blog: [Avalonia with Fragment Shaders](https://avaloniaui.net/blog/avalonia-with-fragment-shaders) 66 | * ...based on work by [Wiesław Šoltés](https://github.com/wieslawsoltes/EffectsDemo). 67 | 68 | The project is licensed under the Creative Commons Attribution-NonCommercial-ShareAlike 3.0 Unported License. 69 | 70 | ## Useful Resources 71 | 72 | - [Avalonia UI Documentation](https://docs.avaloniaui.net/) 73 | - [SKSL Shader Language](https://skia.org/docs/user/sksl/) 74 | - [The Oldschool PC Font Resource](https://int10h.org/oldschool-pc-fonts/fontlist/font?ibm_vga_8x16) 75 | 76 | --- 77 | 78 | Follow me on Twitter for more updates: [@deanthecoder](https://twitter.com/deanthecoder). 79 | -------------------------------------------------------------------------------- /CrtTextBox/Assets/crt.sksl: -------------------------------------------------------------------------------- 1 | // 2 | // ╓――――――――――――――――――╖ 3 | // ║ CRT Effect ║░ 4 | // ║ by ║░ 5 | // ║ DeanTheCoder ║░ 6 | // ╙――――――――――――――――――╜░ 7 | // ░░░░░░░░░░░░░░░░░░░░ 8 | // 9 | // Effects: Fish eye, scan lines, vignette, screen jitter, 10 | // background noise, electron bar, shadows, 11 | // screen glare, fake surround (with reflections). 12 | // 13 | // License: Creative Commons Attribution-NonCommercial-ShareAlike 3.0 Unported License 14 | 15 | uniform float2 iResolution; // ShaderControl size 16 | uniform float iTime; 17 | uniform shader iImage1; // Source control image, sampled multiple times per second. 18 | uniform float2 iImageResolution; // Source control size. 19 | 20 | // Parameterized values 21 | uniform float brightnessBoost; // 1.0 = no boost. 22 | uniform float enableScanlines; // 1.0 to enable, 0.0 to disable 23 | uniform float enableSurround; // 1.0 to enable, 0.0 to disable 24 | uniform float enableSignalDistortion; // 1.0 to enable, 0.0 to disable 25 | uniform float enableShadows; // 1.0 to enable, 0.0 to disabl 26 | 27 | float smoothstep(float edge0, float edge1, float x) 28 | { 29 | float t = clamp((x - edge0) / (edge1 - edge0), 0.0, 1.0); 30 | return t * t * (3.0 - 2.0 * t); 31 | } 32 | 33 | float2 fisheye(float2 uv) 34 | { 35 | float r = 2.5; 36 | uv *= 1.05; 37 | return r * uv / sqrt(r * r - dot(uv, uv)); 38 | } 39 | 40 | float bar(float y) 41 | { 42 | y += 0.5; 43 | y = fract(y * 0.7 - iTime * 0.1); 44 | return smoothstep(0.7, 0.98, y) + smoothstep(0.98, 1.0, 1.-y); 45 | } 46 | 47 | float h21(float2 p) 48 | { 49 | float3 p3 = fract(float3(p.xyx) * float3(0.1031, 0.11369, 0.13787)); 50 | p3 += dot(p3, p3.yzx + 19.19); 51 | return fract((p3.x + p3.y) * p3.z); 52 | } 53 | 54 | float4 main(float2 fragCoord) 55 | { 56 | float2 res = iImageResolution; 57 | float fadeOn = 0.1 + 0.9 * smoothstep(0.5, 3.0, iTime); 58 | 59 | // UV coords in the range of -0.5 to 0.5 60 | float2 uv = (fragCoord / iImageResolution) - 0.5; 61 | 62 | // Apply fisheye and border effect (if enabled). 63 | float2 st = enableSurround > 0.5 ? fisheye(uv) : uv; 64 | 65 | float ns = h21(fragCoord); // Random number, to use later. 66 | 67 | // Monitor screen. 68 | float rnd = h21(fragCoord + iTime); // Jitter. 69 | 70 | float2 tuv = (st + 0.5) * res + float2(rnd * enableSignalDistortion * 0.5, 0); 71 | float3 imageRgb = float3(0); 72 | float ampSum = 0.0; 73 | for (float dx = -1.0; dx < 1.0; dx += 0.125) 74 | { 75 | for (float dy = -1.0; dy < 1.0; dy += 0.125) 76 | { 77 | // Multiple samples to add 'bloom'. 78 | float amp = exp(length(float2(dx, dy)) * -2.0); 79 | imageRgb += amp * sample(iImage1, tuv + float2(dx, dy) * 15.0).rgb; 80 | ampSum += amp; 81 | } 82 | } 83 | imageRgb /= ampSum; 84 | imageRgb = sample(iImage1, tuv).rgb * 0.7 + 0.5 * imageRgb; 85 | imageRgb *= fadeOn; 86 | 87 | float bev = enableSurround > 0.5 ? (max(abs(st.x), abs(st.y)) - 0.498) / 0.035 : 0.0; 88 | if (bev > 0.0) 89 | { 90 | // We're somewhere outside the CRT screen area. 91 | float3 col = float3(0.68, 0.68, 0.592); 92 | if (bev > 1.0) 93 | { 94 | // Monitor face. 95 | col -= ns * 0.05; 96 | } 97 | else 98 | { 99 | // Bevel area. 100 | col *= mix(0.1, 1.0, bev); 101 | col = mix(imageRgb * 0.5, col, 0.5 + 0.5 * smoothstep(0.0, 0.4, bev)); 102 | col = col - float3(0.0, 0.05, 0.1) * ns; 103 | 104 | // Shadow. 105 | if (enableShadows > 0 && uv.y < 0.0) 106 | col *= min(1.0, 0.6 * smoothstep(0.8, 1.0, bev) + 0.8 + smoothstep(0.4, 0.3, length(uv * float2(0.4, 1.0)))); 107 | 108 | // Screen reflection in the bevel. 109 | float dir = sign(-uv.x); 110 | float3 tint = float3(0); 111 | for (float i = -5.0; i < 5.0; i++) 112 | { 113 | for (float j = -5.0; j < 5.0; j++) 114 | tint += sample(iImage1, (st * 0.9 + float2(dir * i, j * 2.0) * 0.002 + 0.5) * res).rgb * fadeOn; 115 | } 116 | 117 | tint /= 80.0; 118 | col = mix(tint, col, 0.8 + 0.2 * bev); 119 | } 120 | 121 | return vec4(col, 1.0); 122 | } 123 | 124 | float lum = 1.0; 125 | 126 | // Background noise. 127 | lum += enableSignalDistortion * (rnd - 0.5) * 0.2; 128 | 129 | // Scrolling electron bar. 130 | lum += enableSignalDistortion * bar(uv.y) * 0.2; 131 | 132 | // Apply scanlines (if enabled). 133 | if (enableScanlines > 0.5 && (int(fragCoord.y) % 2) == 0) 134 | lum *= 0.8 + 0.2 * pow(1.0 - (imageRgb.r + imageRgb.g + imageRgb.b) / 3.0, 1.0); 135 | 136 | // Apply main text color tint. 137 | float3 col = imageRgb * lum * pow(brightnessBoost, 2.0); 138 | 139 | if (enableShadows > 0.5) 140 | { 141 | // Screen shadow. 142 | float bright = 1.0; 143 | if (uv.y < 0.0) 144 | bright = smoothstep(0.43, 0.38, length(uv * float2(0.4, 1.0))); 145 | col *= min(1.0, 0.3 + 0.7 * (bright + clamp(max(max(col.r, col.g), col.b), 0.0, 1.0))); 146 | 147 | // Glare. 148 | col = mix(col, float3(0.5 + 0.5 * ns), bright * 0.25 * smoothstep(0.7, 0.0, length((uv - float2(0.15, -0.3)) * float2(1.0, 2.0)))); 149 | 150 | // Vignette. 151 | col *= 1.0 - 1.2 * dot(uv, uv); 152 | } 153 | 154 | return float4(col, 1.0); 155 | } 156 | -------------------------------------------------------------------------------- /CrtTextBox/ShaderControl.cs: -------------------------------------------------------------------------------- 1 | // Code authored by Dean Edis (DeanTheCoder). 2 | // Anyone is free to copy, modify, use, compile, or distribute this software, 3 | // either in source code form or as a compiled binary, for any non-commercial 4 | // purpose. 5 | // 6 | // If you modify the code, please retain this copyright header, 7 | // and consider contributing back to the repository or letting us know 8 | // about your modifications. Your contributions are valued! 9 | // 10 | // THE SOFTWARE IS PROVIDED AS IS, WITHOUT WARRANTY OF ANY KIND. 11 | using System; 12 | using System.Collections.Generic; 13 | using System.IO; 14 | using System.Numerics; 15 | using Avalonia; 16 | using Avalonia.Controls; 17 | using Avalonia.Media; 18 | using Avalonia.Media.Imaging; 19 | using Avalonia.Platform; 20 | using Avalonia.Rendering.Composition; 21 | using Avalonia.Skia; 22 | using Avalonia.Threading; 23 | using SkiaSharp; 24 | 25 | namespace RenderTest; 26 | 27 | /// 28 | /// A custom Avalonia control that applies a shader effect to a visual element. 29 | /// 30 | public class ShaderControl : UserControl 31 | { 32 | private readonly Dictionary> m_uniforms = new Dictionary>(); 33 | private CompositionCustomVisual m_customVisual; 34 | private Control m_controlSource; 35 | private SKBitmap m_sourceControlBitmap; 36 | private ShaderVisualHandler m_visualHandler; 37 | private SKBitmap m_blurredControlBitmap; 38 | private RenderTargetBitmap m_renderTargetBitmap; 39 | 40 | /// 41 | /// Defines the Uri property for the shader source. 42 | /// 43 | public static readonly StyledProperty ShaderUriProperty = 44 | AvaloniaProperty.Register(nameof(ShaderUri)); 45 | 46 | /// 47 | /// Defines the sampling frame rate of the source control. 48 | /// 49 | public static readonly StyledProperty FpsProperty = AvaloniaProperty.Register(nameof(Fps), 30); 50 | 51 | /// 52 | /// Defines whether phosphor trails are added. 53 | /// 54 | public static readonly StyledProperty TrailsProperty = AvaloniaProperty.Register(nameof(Trails)); 55 | 56 | static ShaderControl() 57 | { 58 | AffectsRender(ShaderUriProperty); 59 | AffectsMeasure(ShaderUriProperty); 60 | } 61 | 62 | /// 63 | /// Gets or sets the frames per second (FPS) at which the source control is sampled. 64 | /// 65 | public int Fps 66 | { 67 | get => GetValue(FpsProperty); 68 | set => SetValue(FpsProperty, value); 69 | } 70 | 71 | /// 72 | /// Gets or sets the URI of the shader to be applied. 73 | /// 74 | public Uri ShaderUri 75 | { 76 | get => GetValue(ShaderUriProperty); 77 | set => SetValue(ShaderUriProperty, value); 78 | } 79 | 80 | /// 81 | /// Gets or sets whether phosphor trails are added. 82 | /// 83 | public bool Trails 84 | { 85 | get => GetValue(TrailsProperty); 86 | set => SetValue(TrailsProperty, value); 87 | } 88 | 89 | /// 90 | /// Gets or sets the control source to which the shader effect will be applied. 91 | /// 92 | /// 93 | /// Thrown if the control source is already set. 94 | /// 95 | /// 96 | /// Thrown if the control source is set to null. 97 | /// 98 | public Control ControlSource 99 | { 100 | get => m_controlSource; 101 | set 102 | { 103 | if (m_controlSource != null) 104 | throw new InvalidOperationException($"{nameof(ControlSource)} has already been set."); 105 | m_controlSource = value ?? throw new ArgumentNullException(); 106 | 107 | DispatcherTimer.Run(() => 108 | { 109 | RenderSourceAsImage(); 110 | return true; 111 | }, TimeSpan.FromSeconds(1.0 / Fps)); 112 | } 113 | } 114 | 115 | /// 116 | /// Call to set a constant boolean uniform value, to be passed (as 0.0 or 1.0) to the shader code each frame. 117 | /// 118 | /// 119 | /// To receive the value in the shader, use: 120 | /// uniform float iName; 121 | /// 122 | public void AddUniform(string name, bool value) => 123 | AddUniform(name, value ? 1.0f : 0.0f); 124 | 125 | /// 126 | /// Call to set a constant uniform float/float2/float3/float4 value, to be passed to the shader code each frame. 127 | /// 128 | /// 129 | /// To receive the values in the shader, use: 130 | /// uniform float3 iName; 131 | /// 132 | public void AddUniform(string name, params float[] values) => 133 | AddUniform(name, () => values); 134 | 135 | /// 136 | /// Call to set a variable uniform value using a callback function, to be passed to the shader code each frame. 137 | /// 138 | /// 139 | /// To receive the value in the shader, use: 140 | /// uniform float3 iName; 141 | /// 142 | public void AddUniform(string name, Func getValue) => 143 | m_uniforms[name] = getValue; 144 | 145 | /// 146 | /// Called in response to the source control changing state, this method renders the source 147 | /// control into a bitmap, allowing for its appearance to later be modified when displayed 148 | /// to the screen. 149 | /// 150 | private void RenderSourceAsImage() 151 | { 152 | if (Bounds.Width == 0 || Bounds.Height == 0) 153 | return; 154 | 155 | // Check if the control bitmap needs to be recreated (e.g., if size has changed). 156 | if (m_sourceControlBitmap == null || m_sourceControlBitmap.Width != (int)Bounds.Width || m_sourceControlBitmap.Height != (int)Bounds.Height) 157 | { 158 | m_sourceControlBitmap?.Dispose(); 159 | m_sourceControlBitmap = new SKBitmap(new SKImageInfo((int)Bounds.Width, (int)Bounds.Height, SKColorType.Rgba8888, SKAlphaType.Premul)); 160 | m_blurredControlBitmap?.Dispose(); 161 | m_blurredControlBitmap = new SKBitmap(new SKImageInfo((int)Bounds.Width, (int)Bounds.Height, SKImageInfo.PlatformColorType, SKAlphaType.Premul)); 162 | m_renderTargetBitmap?.Dispose(); 163 | m_renderTargetBitmap = new RenderTargetBitmap(new PixelSize(m_sourceControlBitmap.Width, m_sourceControlBitmap.Height)); 164 | } 165 | 166 | // Get the image of the Avalonia source control. 167 | m_renderTargetBitmap.Render(ControlSource); 168 | 169 | // Convert it to an SKBitmap. 170 | m_renderTargetBitmap.CopyPixels( 171 | new PixelRect(0, 0, m_blurredControlBitmap.Width, m_blurredControlBitmap.Height), 172 | m_blurredControlBitmap.GetPixels(), 173 | m_blurredControlBitmap.ByteCount, 174 | m_blurredControlBitmap.RowBytes); 175 | 176 | if (Trails) 177 | { 178 | // Combine image with the previous frame, to add motion blur. 179 | using var paint = new SKPaint(); 180 | paint.Color = new SKColor(0xff, 0xff, 0xff, 100); 181 | paint.BlendMode = SKBlendMode.SrcOver; 182 | using var canvas = new SKCanvas(m_sourceControlBitmap); 183 | canvas.DrawBitmap(m_blurredControlBitmap, 0, 0, paint); 184 | } 185 | else 186 | { 187 | using var canvas = new SKCanvas(m_sourceControlBitmap); 188 | canvas.DrawBitmap(m_blurredControlBitmap, 0, 0); 189 | } 190 | 191 | // Set the image to send to the shader for display. 192 | m_visualHandler.SourceBitmap = m_sourceControlBitmap; 193 | } 194 | 195 | private Size GetShaderSize() => m_controlSource?.Bounds.Size ?? new Size(512, 512); 196 | 197 | protected override Size MeasureOverride(Size availableSize) => 198 | ShaderUri != null ? Stretch.Fill.CalculateSize(availableSize, GetShaderSize()) : new Size(); 199 | 200 | protected override Size ArrangeOverride(Size finalSize) 201 | { 202 | var source = ShaderUri; 203 | if (source == null) 204 | return new Size(); 205 | 206 | var sourceSize = GetShaderSize(); 207 | return Stretch.Fill.CalculateSize(finalSize, sourceSize); 208 | } 209 | 210 | protected override void OnAttachedToVisualTree(VisualTreeAttachmentEventArgs e) 211 | { 212 | base.OnAttachedToVisualTree(e); 213 | 214 | IsHitTestVisible = false; 215 | 216 | var elemVisual = ElementComposition.GetElementVisual(this); 217 | var compositor = elemVisual?.Compositor; 218 | if (compositor is null) 219 | return; 220 | 221 | m_visualHandler = new ShaderVisualHandler(m_uniforms); 222 | m_customVisual = compositor.CreateCustomVisual(m_visualHandler); 223 | ElementComposition.SetElementChildVisual(this, m_customVisual); 224 | 225 | LayoutUpdated += OnLayoutUpdated; 226 | 227 | m_customVisual.Size = new Vector2((float)Bounds.Size.Width, (float)Bounds.Size.Height); 228 | 229 | m_customVisual.SendHandlerMessage( 230 | new ShaderVisualHandler.DrawPayload( 231 | ShaderVisualHandler.Command.Update, 232 | null, 233 | GetShaderSize(), 234 | Bounds.Size)); 235 | 236 | Start(); 237 | } 238 | 239 | protected override void OnDetachedFromVisualTree(VisualTreeAttachmentEventArgs e) 240 | { 241 | base.OnDetachedFromVisualTree(e); 242 | LayoutUpdated -= OnLayoutUpdated; 243 | 244 | Stop(); 245 | DisposeImpl(); 246 | } 247 | 248 | private void OnLayoutUpdated(object sender, EventArgs e) 249 | { 250 | if (m_customVisual == null) 251 | return; 252 | 253 | m_customVisual.Size = new Vector2((float)Bounds.Size.Width, (float)Bounds.Size.Height); 254 | 255 | m_customVisual.SendHandlerMessage( 256 | new ShaderVisualHandler.DrawPayload( 257 | ShaderVisualHandler.Command.Update, 258 | null, 259 | GetShaderSize(), 260 | Bounds.Size)); 261 | } 262 | 263 | private void Start() 264 | { 265 | m_customVisual?.SendHandlerMessage( 266 | new ShaderVisualHandler.DrawPayload( 267 | ShaderVisualHandler.Command.Start, 268 | ShaderUri, 269 | GetShaderSize(), 270 | Bounds.Size)); 271 | InvalidateVisual(); 272 | } 273 | 274 | private void Stop() => 275 | m_customVisual?.SendHandlerMessage(new ShaderVisualHandler.DrawPayload(ShaderVisualHandler.Command.Stop)); 276 | 277 | private void DisposeImpl() => 278 | m_customVisual?.SendHandlerMessage(new ShaderVisualHandler.DrawPayload(ShaderVisualHandler.Command.Dispose)); 279 | 280 | /// 281 | /// Apply new shader code. 282 | /// 283 | public void SetSksl(string sksl) 284 | { 285 | Stop(); 286 | m_visualHandler.ShaderCode = sksl; 287 | Start(); 288 | } 289 | 290 | /// 291 | /// Handles custom visual drawing for the shader effect. 292 | /// 293 | private class ShaderVisualHandler : CompositionCustomVisualHandler 294 | { 295 | private readonly object m_sync = new object(); 296 | private readonly Dictionary> m_customUniforms; 297 | private Size? m_boundsSize; 298 | private SKRuntimeEffect m_effect; 299 | private bool m_isDisposed; 300 | private bool m_running; 301 | private Size? m_shaderSize; 302 | private SKRuntimeEffectUniforms m_uniforms; 303 | 304 | internal string ShaderCode { get; set; } 305 | 306 | public ShaderVisualHandler(Dictionary> uniforms) 307 | { 308 | m_customUniforms = uniforms; 309 | m_customUniforms["iTime"] = () => new[] { (float)CompositionNow.TotalSeconds }; 310 | } 311 | 312 | /// 313 | /// Gets or sets the source bitmap that the shader effect is applied to. 314 | /// 315 | public SKBitmap SourceBitmap { get; set; } 316 | 317 | /// 318 | /// Handles messages sent to the visual handler, such as starting or stopping the shader effect. 319 | /// 320 | public override void OnMessage(object message) 321 | { 322 | if (message is not DrawPayload msg) 323 | return; 324 | 325 | switch (msg) 326 | { 327 | case { Command: Command.Start, ShaderCode: { } uri, ShaderSize: { } shaderSize, Size: { } size }: 328 | { 329 | if (ShaderCode == null) 330 | { 331 | using var stream = AssetLoader.Open(uri); 332 | using var txt = new StreamReader(stream); 333 | ShaderCode = txt.ReadToEnd(); 334 | } 335 | 336 | m_effect = SKRuntimeEffect.Create(ShaderCode, out var errorText); 337 | if (m_effect == null) 338 | Console.WriteLine($"Shader compilation error: {errorText}"); 339 | 340 | m_shaderSize = shaderSize; 341 | m_running = true; 342 | m_boundsSize = size; 343 | RegisterForNextAnimationFrameUpdate(); 344 | break; 345 | } 346 | case { Command: Command.Update, ShaderSize: { } shaderSize, Size: { } size }: 347 | { 348 | m_shaderSize = shaderSize; 349 | m_boundsSize = size; 350 | RegisterForNextAnimationFrameUpdate(); 351 | break; 352 | } 353 | case { Command: Command.Stop }: 354 | { 355 | m_running = false; 356 | break; 357 | } 358 | case { Command: Command.Dispose }: 359 | { 360 | DisposeImpl(); 361 | break; 362 | } 363 | } 364 | } 365 | 366 | /// 367 | /// Updates the shader effect on each animation frame, and schedules the next frame to be processed. 368 | /// 369 | public override void OnAnimationFrameUpdate() 370 | { 371 | if (!m_running || m_isDisposed) 372 | return; 373 | 374 | Invalidate(); 375 | RegisterForNextAnimationFrameUpdate(); 376 | } 377 | 378 | /// 379 | /// Draws the shader effect onto the given SkiaSharp canvas. 380 | /// 381 | private void Draw(SKCanvas canvas) 382 | { 383 | if (m_isDisposed || m_effect is null) 384 | return; 385 | 386 | canvas.Save(); 387 | 388 | var targetWidth = (float)(m_shaderSize?.Width ?? 0.0); 389 | var targetHeight = (float)(m_shaderSize?.Height ?? 0.0); 390 | 391 | m_uniforms ??= new SKRuntimeEffectUniforms(m_effect); 392 | 393 | m_uniforms["iResolution"] = new[] 394 | { 395 | targetWidth, targetHeight 396 | }; 397 | 398 | foreach (var (name, getValue) in m_customUniforms) 399 | m_uniforms[name] = getValue(); 400 | 401 | SKRuntimeEffectChildren children = null; 402 | using var imageShader = SourceBitmap?.ToShader(); 403 | if (imageShader != null) 404 | { 405 | children = new SKRuntimeEffectChildren(m_effect) 406 | { 407 | ["iImage1"] = imageShader 408 | }; 409 | m_uniforms["iImageResolution"] = new float[] 410 | { 411 | SourceBitmap.Width, SourceBitmap.Height 412 | }; 413 | } 414 | 415 | using (var paint = new SKPaint()) 416 | using (var shader = children != null ? m_effect.ToShader(false, m_uniforms, children) : m_effect.ToShader(false, m_uniforms)) 417 | { 418 | paint.Shader = shader; 419 | paint.FilterQuality = SKFilterQuality.Low; 420 | canvas.DrawRect(SKRect.Create(targetWidth, targetHeight), paint); 421 | } 422 | 423 | canvas.Restore(); 424 | } 425 | 426 | /// 427 | /// Renders the shader effect within the context of the Avalonia ImmediateDrawingContext. 428 | /// 429 | /// The drawing context. 430 | public override void OnRender(ImmediateDrawingContext context) 431 | { 432 | lock (m_sync) 433 | { 434 | if (m_isDisposed) 435 | return; 436 | 437 | var leaseFeature = context.TryGetFeature(); 438 | if (leaseFeature is null) 439 | return; 440 | 441 | var rb = GetRenderBounds(); 442 | var size = m_boundsSize ?? rb.Size; 443 | var viewPort = new Rect(rb.Size); 444 | var sourceSize = m_shaderSize!.Value; 445 | 446 | if (sourceSize.Width <= 0 || sourceSize.Height <= 0) 447 | return; 448 | 449 | var scale = Stretch.Fill.CalculateScaling(rb.Size, sourceSize); 450 | var scaledSize = sourceSize * scale; 451 | var destRect = viewPort 452 | .CenterRect(new Rect(scaledSize)) 453 | .Intersect(viewPort); 454 | var sourceRect = new Rect(sourceSize) 455 | .CenterRect(new Rect(destRect.Size / scale)); 456 | 457 | var bounds = SKRect.Create(new SKPoint(), new SKSize((float)size.Width, (float)size.Height)); 458 | 459 | var scaleMatrix = Matrix.CreateScale( 460 | destRect.Width / sourceRect.Width, 461 | destRect.Height / sourceRect.Height); 462 | 463 | var translateMatrix = Matrix.CreateTranslation( 464 | (-sourceRect.X + destRect.X) - bounds.Top, 465 | (-sourceRect.Y + destRect.Y) - bounds.Left); 466 | 467 | using (context.PushClip(destRect)) 468 | using (context.PushPostTransform(translateMatrix * scaleMatrix)) 469 | { 470 | using var lease = leaseFeature.Lease(); 471 | Draw(lease.SkCanvas); 472 | } 473 | } 474 | } 475 | 476 | private void DisposeImpl() 477 | { 478 | lock (m_sync) 479 | { 480 | if (m_isDisposed) return; 481 | m_isDisposed = true; 482 | m_effect?.Dispose(); 483 | m_uniforms?.Reset(); 484 | m_running = false; 485 | } 486 | } 487 | 488 | /// 489 | /// Enum representing commands sent to the shader visual handler. 490 | /// 491 | public enum Command 492 | { 493 | Start, 494 | Stop, 495 | Update, 496 | Dispose 497 | } 498 | 499 | /// 500 | /// A struct representing the payload for draw commands sent to the shader visual handler. 501 | /// 502 | public record struct DrawPayload( 503 | Command Command, 504 | Uri ShaderCode = default, 505 | Size? ShaderSize = default, 506 | Size? Size = default); 507 | } 508 | } -------------------------------------------------------------------------------- /CrtTextBox/Assets/Fonts/VGA/LICENSE.TXT: -------------------------------------------------------------------------------- 1 | Attribution-ShareAlike 4.0 International 2 | 3 | ======================================================================= 4 | 5 | Creative Commons Corporation ("Creative Commons") is not a law firm and 6 | does not provide legal services or legal advice. Distribution of 7 | Creative Commons public licenses does not create a lawyer-client or 8 | other relationship. Creative Commons makes its licenses and related 9 | information available on an "as-is" basis. Creative Commons gives no 10 | warranties regarding its licenses, any material licensed under their 11 | terms and conditions, or any related information. Creative Commons 12 | disclaims all liability for damages resulting from their use to the 13 | fullest extent possible. 14 | 15 | Using Creative Commons Public Licenses 16 | 17 | Creative Commons public licenses provide a standard set of terms and 18 | conditions that creators and other rights holders may use to share 19 | original works of authorship and other material subject to copyright 20 | and certain other rights specified in the public license below. The 21 | following considerations are for informational purposes only, are not 22 | exhaustive, and do not form part of our licenses. 23 | 24 | Considerations for licensors: Our public licenses are 25 | intended for use by those authorized to give the public 26 | permission to use material in ways otherwise restricted by 27 | copyright and certain other rights. Our licenses are 28 | irrevocable. Licensors should read and understand the terms 29 | and conditions of the license they choose before applying it. 30 | Licensors should also secure all rights necessary before 31 | applying our licenses so that the public can reuse the 32 | material as expected. Licensors should clearly mark any 33 | material not subject to the license. This includes other CC- 34 | licensed material, or material used under an exception or 35 | limitation to copyright. More considerations for licensors: 36 | wiki.creativecommons.org/Considerations_for_licensors 37 | 38 | Considerations for the public: By using one of our public 39 | licenses, a licensor grants the public permission to use the 40 | licensed material under specified terms and conditions. If 41 | the licensor's permission is not necessary for any reason--for 42 | example, because of any applicable exception or limitation to 43 | copyright--then that use is not regulated by the license. Our 44 | licenses grant only permissions under copyright and certain 45 | other rights that a licensor has authority to grant. Use of 46 | the licensed material may still be restricted for other 47 | reasons, including because others have copyright or other 48 | rights in the material. A licensor may make special requests, 49 | such as asking that all changes be marked or described. 50 | Although not required by our licenses, you are encouraged to 51 | respect those requests where reasonable. More_considerations 52 | for the public: 53 | wiki.creativecommons.org/Considerations_for_licensees 54 | 55 | ======================================================================= 56 | 57 | Creative Commons Attribution-ShareAlike 4.0 International Public 58 | License 59 | 60 | By exercising the Licensed Rights (defined below), You accept and agree 61 | to be bound by the terms and conditions of this Creative Commons 62 | Attribution-ShareAlike 4.0 International Public License ("Public 63 | License"). To the extent this Public License may be interpreted as a 64 | contract, You are granted the Licensed Rights in consideration of Your 65 | acceptance of these terms and conditions, and the Licensor grants You 66 | such rights in consideration of benefits the Licensor receives from 67 | making the Licensed Material available under these terms and 68 | conditions. 69 | 70 | 71 | Section 1 -- Definitions. 72 | 73 | a. Adapted Material means material subject to Copyright and Similar 74 | Rights that is derived from or based upon the Licensed Material 75 | and in which the Licensed Material is translated, altered, 76 | arranged, transformed, or otherwise modified in a manner requiring 77 | permission under the Copyright and Similar Rights held by the 78 | Licensor. For purposes of this Public License, where the Licensed 79 | Material is a musical work, performance, or sound recording, 80 | Adapted Material is always produced where the Licensed Material is 81 | synched in timed relation with a moving image. 82 | 83 | b. Adapter's License means the license You apply to Your Copyright 84 | and Similar Rights in Your contributions to Adapted Material in 85 | accordance with the terms and conditions of this Public License. 86 | 87 | c. BY-SA Compatible License means a license listed at 88 | creativecommons.org/compatiblelicenses, approved by Creative 89 | Commons as essentially the equivalent of this Public License. 90 | 91 | d. Copyright and Similar Rights means copyright and/or similar rights 92 | closely related to copyright including, without limitation, 93 | performance, broadcast, sound recording, and Sui Generis Database 94 | Rights, without regard to how the rights are labeled or 95 | categorized. For purposes of this Public License, the rights 96 | specified in Section 2(b)(1)-(2) are not Copyright and Similar 97 | Rights. 98 | 99 | e. Effective Technological Measures means those measures that, in the 100 | absence of proper authority, may not be circumvented under laws 101 | fulfilling obligations under Article 11 of the WIPO Copyright 102 | Treaty adopted on December 20, 1996, and/or similar international 103 | agreements. 104 | 105 | f. Exceptions and Limitations means fair use, fair dealing, and/or 106 | any other exception or limitation to Copyright and Similar Rights 107 | that applies to Your use of the Licensed Material. 108 | 109 | g. License Elements means the license attributes listed in the name 110 | of a Creative Commons Public License. The License Elements of this 111 | Public License are Attribution and ShareAlike. 112 | 113 | h. Licensed Material means the artistic or literary work, database, 114 | or other material to which the Licensor applied this Public 115 | License. 116 | 117 | i. Licensed Rights means the rights granted to You subject to the 118 | terms and conditions of this Public License, which are limited to 119 | all Copyright and Similar Rights that apply to Your use of the 120 | Licensed Material and that the Licensor has authority to license. 121 | 122 | j. Licensor means the individual(s) or entity(ies) granting rights 123 | under this Public License. 124 | 125 | k. Share means to provide material to the public by any means or 126 | process that requires permission under the Licensed Rights, such 127 | as reproduction, public display, public performance, distribution, 128 | dissemination, communication, or importation, and to make material 129 | available to the public including in ways that members of the 130 | public may access the material from a place and at a time 131 | individually chosen by them. 132 | 133 | l. Sui Generis Database Rights means rights other than copyright 134 | resulting from Directive 96/9/EC of the European Parliament and of 135 | the Council of 11 March 1996 on the legal protection of databases, 136 | as amended and/or succeeded, as well as other essentially 137 | equivalent rights anywhere in the world. 138 | 139 | m. You means the individual or entity exercising the Licensed Rights 140 | under this Public License. Your has a corresponding meaning. 141 | 142 | 143 | Section 2 -- Scope. 144 | 145 | a. License grant. 146 | 147 | 1. Subject to the terms and conditions of this Public License, 148 | the Licensor hereby grants You a worldwide, royalty-free, 149 | non-sublicensable, non-exclusive, irrevocable license to 150 | exercise the Licensed Rights in the Licensed Material to: 151 | 152 | a. reproduce and Share the Licensed Material, in whole or 153 | in part; and 154 | 155 | b. produce, reproduce, and Share Adapted Material. 156 | 157 | 2. Exceptions and Limitations. For the avoidance of doubt, where 158 | Exceptions and Limitations apply to Your use, this Public 159 | License does not apply, and You do not need to comply with 160 | its terms and conditions. 161 | 162 | 3. Term. The term of this Public License is specified in Section 163 | 6(a). 164 | 165 | 4. Media and formats; technical modifications allowed. The 166 | Licensor authorizes You to exercise the Licensed Rights in 167 | all media and formats whether now known or hereafter created, 168 | and to make technical modifications necessary to do so. The 169 | Licensor waives and/or agrees not to assert any right or 170 | authority to forbid You from making technical modifications 171 | necessary to exercise the Licensed Rights, including 172 | technical modifications necessary to circumvent Effective 173 | Technological Measures. For purposes of this Public License, 174 | simply making modifications authorized by this Section 2(a) 175 | (4) never produces Adapted Material. 176 | 177 | 5. Downstream recipients. 178 | 179 | a. Offer from the Licensor -- Licensed Material. Every 180 | recipient of the Licensed Material automatically 181 | receives an offer from the Licensor to exercise the 182 | Licensed Rights under the terms and conditions of this 183 | Public License. 184 | 185 | b. Additional offer from the Licensor -- Adapted Material. 186 | Every recipient of Adapted Material from You 187 | automatically receives an offer from the Licensor to 188 | exercise the Licensed Rights in the Adapted Material 189 | under the conditions of the Adapter's License You apply. 190 | 191 | c. No downstream restrictions. You may not offer or impose 192 | any additional or different terms or conditions on, or 193 | apply any Effective Technological Measures to, the 194 | Licensed Material if doing so restricts exercise of the 195 | Licensed Rights by any recipient of the Licensed 196 | Material. 197 | 198 | 6. No endorsement. Nothing in this Public License constitutes or 199 | may be construed as permission to assert or imply that You 200 | are, or that Your use of the Licensed Material is, connected 201 | with, or sponsored, endorsed, or granted official status by, 202 | the Licensor or others designated to receive attribution as 203 | provided in Section 3(a)(1)(A)(i). 204 | 205 | b. Other rights. 206 | 207 | 1. Moral rights, such as the right of integrity, are not 208 | licensed under this Public License, nor are publicity, 209 | privacy, and/or other similar personality rights; however, to 210 | the extent possible, the Licensor waives and/or agrees not to 211 | assert any such rights held by the Licensor to the limited 212 | extent necessary to allow You to exercise the Licensed 213 | Rights, but not otherwise. 214 | 215 | 2. Patent and trademark rights are not licensed under this 216 | Public License. 217 | 218 | 3. To the extent possible, the Licensor waives any right to 219 | collect royalties from You for the exercise of the Licensed 220 | Rights, whether directly or through a collecting society 221 | under any voluntary or waivable statutory or compulsory 222 | licensing scheme. In all other cases the Licensor expressly 223 | reserves any right to collect such royalties. 224 | 225 | 226 | Section 3 -- License Conditions. 227 | 228 | Your exercise of the Licensed Rights is expressly made subject to the 229 | following conditions. 230 | 231 | a. Attribution. 232 | 233 | 1. If You Share the Licensed Material (including in modified 234 | form), You must: 235 | 236 | a. retain the following if it is supplied by the Licensor 237 | with the Licensed Material: 238 | 239 | i. identification of the creator(s) of the Licensed 240 | Material and any others designated to receive 241 | attribution, in any reasonable manner requested by 242 | the Licensor (including by pseudonym if 243 | designated); 244 | 245 | ii. a copyright notice; 246 | 247 | iii. a notice that refers to this Public License; 248 | 249 | iv. a notice that refers to the disclaimer of 250 | warranties; 251 | 252 | v. a URI or hyperlink to the Licensed Material to the 253 | extent reasonably practicable; 254 | 255 | b. indicate if You modified the Licensed Material and 256 | retain an indication of any previous modifications; and 257 | 258 | c. indicate the Licensed Material is licensed under this 259 | Public License, and include the text of, or the URI or 260 | hyperlink to, this Public License. 261 | 262 | 2. You may satisfy the conditions in Section 3(a)(1) in any 263 | reasonable manner based on the medium, means, and context in 264 | which You Share the Licensed Material. For example, it may be 265 | reasonable to satisfy the conditions by providing a URI or 266 | hyperlink to a resource that includes the required 267 | information. 268 | 269 | 3. If requested by the Licensor, You must remove any of the 270 | information required by Section 3(a)(1)(A) to the extent 271 | reasonably practicable. 272 | 273 | b. ShareAlike. 274 | 275 | In addition to the conditions in Section 3(a), if You Share 276 | Adapted Material You produce, the following conditions also apply. 277 | 278 | 1. The Adapter's License You apply must be a Creative Commons 279 | license with the same License Elements, this version or 280 | later, or a BY-SA Compatible License. 281 | 282 | 2. You must include the text of, or the URI or hyperlink to, the 283 | Adapter's License You apply. You may satisfy this condition 284 | in any reasonable manner based on the medium, means, and 285 | context in which You Share Adapted Material. 286 | 287 | 3. You may not offer or impose any additional or different terms 288 | or conditions on, or apply any Effective Technological 289 | Measures to, Adapted Material that restrict exercise of the 290 | rights granted under the Adapter's License You apply. 291 | 292 | 293 | Section 4 -- Sui Generis Database Rights. 294 | 295 | Where the Licensed Rights include Sui Generis Database Rights that 296 | apply to Your use of the Licensed Material: 297 | 298 | a. for the avoidance of doubt, Section 2(a)(1) grants You the right 299 | to extract, reuse, reproduce, and Share all or a substantial 300 | portion of the contents of the database; 301 | 302 | b. if You include all or a substantial portion of the database 303 | contents in a database in which You have Sui Generis Database 304 | Rights, then the database in which You have Sui Generis Database 305 | Rights (but not its individual contents) is Adapted Material, 306 | 307 | including for purposes of Section 3(b); and 308 | c. You must comply with the conditions in Section 3(a) if You Share 309 | all or a substantial portion of the contents of the database. 310 | 311 | For the avoidance of doubt, this Section 4 supplements and does not 312 | replace Your obligations under this Public License where the Licensed 313 | Rights include other Copyright and Similar Rights. 314 | 315 | 316 | Section 5 -- Disclaimer of Warranties and Limitation of Liability. 317 | 318 | a. UNLESS OTHERWISE SEPARATELY UNDERTAKEN BY THE LICENSOR, TO THE 319 | EXTENT POSSIBLE, THE LICENSOR OFFERS THE LICENSED MATERIAL AS-IS 320 | AND AS-AVAILABLE, AND MAKES NO REPRESENTATIONS OR WARRANTIES OF 321 | ANY KIND CONCERNING THE LICENSED MATERIAL, WHETHER EXPRESS, 322 | IMPLIED, STATUTORY, OR OTHER. THIS INCLUDES, WITHOUT LIMITATION, 323 | WARRANTIES OF TITLE, MERCHANTABILITY, FITNESS FOR A PARTICULAR 324 | PURPOSE, NON-INFRINGEMENT, ABSENCE OF LATENT OR OTHER DEFECTS, 325 | ACCURACY, OR THE PRESENCE OR ABSENCE OF ERRORS, WHETHER OR NOT 326 | KNOWN OR DISCOVERABLE. WHERE DISCLAIMERS OF WARRANTIES ARE NOT 327 | ALLOWED IN FULL OR IN PART, THIS DISCLAIMER MAY NOT APPLY TO YOU. 328 | 329 | b. TO THE EXTENT POSSIBLE, IN NO EVENT WILL THE LICENSOR BE LIABLE 330 | TO YOU ON ANY LEGAL THEORY (INCLUDING, WITHOUT LIMITATION, 331 | NEGLIGENCE) OR OTHERWISE FOR ANY DIRECT, SPECIAL, INDIRECT, 332 | INCIDENTAL, CONSEQUENTIAL, PUNITIVE, EXEMPLARY, OR OTHER LOSSES, 333 | COSTS, EXPENSES, OR DAMAGES ARISING OUT OF THIS PUBLIC LICENSE OR 334 | USE OF THE LICENSED MATERIAL, EVEN IF THE LICENSOR HAS BEEN 335 | ADVISED OF THE POSSIBILITY OF SUCH LOSSES, COSTS, EXPENSES, OR 336 | DAMAGES. WHERE A LIMITATION OF LIABILITY IS NOT ALLOWED IN FULL OR 337 | IN PART, THIS LIMITATION MAY NOT APPLY TO YOU. 338 | 339 | c. The disclaimer of warranties and limitation of liability provided 340 | above shall be interpreted in a manner that, to the extent 341 | possible, most closely approximates an absolute disclaimer and 342 | waiver of all liability. 343 | 344 | 345 | Section 6 -- Term and Termination. 346 | 347 | a. This Public License applies for the term of the Copyright and 348 | Similar Rights licensed here. However, if You fail to comply with 349 | this Public License, then Your rights under this Public License 350 | terminate automatically. 351 | 352 | b. Where Your right to use the Licensed Material has terminated under 353 | Section 6(a), it reinstates: 354 | 355 | 1. automatically as of the date the violation is cured, provided 356 | it is cured within 30 days of Your discovery of the 357 | violation; or 358 | 359 | 2. upon express reinstatement by the Licensor. 360 | 361 | For the avoidance of doubt, this Section 6(b) does not affect any 362 | right the Licensor may have to seek remedies for Your violations 363 | of this Public License. 364 | 365 | c. For the avoidance of doubt, the Licensor may also offer the 366 | Licensed Material under separate terms or conditions or stop 367 | distributing the Licensed Material at any time; however, doing so 368 | will not terminate this Public License. 369 | 370 | d. Sections 1, 5, 6, 7, and 8 survive termination of this Public 371 | License. 372 | 373 | 374 | Section 7 -- Other Terms and Conditions. 375 | 376 | a. The Licensor shall not be bound by any additional or different 377 | terms or conditions communicated by You unless expressly agreed. 378 | 379 | b. Any arrangements, understandings, or agreements regarding the 380 | Licensed Material not stated herein are separate from and 381 | independent of the terms and conditions of this Public License. 382 | 383 | 384 | Section 8 -- Interpretation. 385 | 386 | a. For the avoidance of doubt, this Public License does not, and 387 | shall not be interpreted to, reduce, limit, restrict, or impose 388 | conditions on any use of the Licensed Material that could lawfully 389 | be made without permission under this Public License. 390 | 391 | b. To the extent possible, if any provision of this Public License is 392 | deemed unenforceable, it shall be automatically reformed to the 393 | minimum extent necessary to make it enforceable. If the provision 394 | cannot be reformed, it shall be severed from this Public License 395 | without affecting the enforceability of the remaining terms and 396 | conditions. 397 | 398 | c. No term or condition of this Public License will be waived and no 399 | failure to comply consented to unless expressly agreed to by the 400 | Licensor. 401 | 402 | d. Nothing in this Public License constitutes or may be interpreted 403 | as a limitation upon, or waiver of, any privileges and immunities 404 | that apply to the Licensor or You, including from the legal 405 | processes of any jurisdiction or authority. 406 | 407 | 408 | ======================================================================= 409 | 410 | Creative Commons is not a party to its public 411 | licenses. Notwithstanding, Creative Commons may elect to apply one of 412 | its public licenses to material it publishes and in those instances 413 | will be considered the “Licensor.” The text of the Creative Commons 414 | public licenses is dedicated to the public domain under the CC0 Public 415 | Domain Dedication. Except for the limited purpose of indicating that 416 | material is shared under a Creative Commons public license or as 417 | otherwise permitted by the Creative Commons policies published at 418 | creativecommons.org/policies, Creative Commons does not authorize the 419 | use of the trademark "Creative Commons" or any other trademark or logo 420 | of Creative Commons without its prior written consent including, 421 | without limitation, in connection with any unauthorized modifications 422 | to any of its public licenses or any other arrangements, 423 | understandings, or agreements concerning use of licensed material. For 424 | the avoidance of doubt, this paragraph does not form part of the 425 | public licenses. 426 | 427 | Creative Commons may be contacted at creativecommons.org. 428 | 429 | --------------------------------------------------------------------------------