vchelaru / FlatRedBall

Cross-platform 2D game engine focused on ultimate productivity built in .NET
http://flatredball.com
MIT License
402 stars 64 forks source link

Update shader documentation #946

Open vchelaru opened 1 year ago

vchelaru commented 1 year ago

C# example:

private SpriteBatch _spriteBatch = null!;
private TimeSpan _effectDuration = TimeSpan.FromSeconds(4);

private void CustomInitialize()
{
    _spriteBatch = new SpriteBatch(FlatRedBallServices.GraphicsDevice);
}

public void Draw(Camera camera)
{
    // flip y axis because SpriteBatch drawing coordinates start from the top-left corner
    //   where positive x is right (same as FRB) and positive y is down (opposite of FRB)
    var drawPosition = SpriteInstance.Position.ToVector2() * new Vector2(1, -1);

    var shader = DefaultSprite;
    SetCommonShaderParameters(shader, camera, drawPosition, _effectDuration, SpriteInstance.TextureScale, SpriteInstance.Texture);

    var spriteColor = new Color(SpriteInstance.Red, SpriteInstance.Green, SpriteInstance.Blue, SpriteInstance.Alpha);
    var origin = new Vector2(SpriteInstance.ScaleX, SpriteInstance.ScaleY) / SpriteInstance.TextureScale;
    SpriteEffects shouldFlip = (SpriteInstance.FlipHorizontal, SpriteInstance.FlipVertical) switch
    {
        (false, false) => SpriteEffects.None,
        (true , false) => SpriteEffects.FlipHorizontally,
        (false, true ) => SpriteEffects.FlipVertically,
        (true , true ) => SpriteEffects.FlipHorizontally | SpriteEffects.FlipVertically,
    };

    _spriteBatch.Begin(effect: shader);
    _spriteBatch.Draw(SpriteInstance.Texture, drawPosition, 
        null, spriteColor, SpriteInstance.RotationZ, origin,
        SpriteInstance.TextureScale, shouldFlip, Position.Z);
    _spriteBatch.End();
}

private void CustomDestroy()
{
    _spriteBatch.Dispose();
}

private static Matrix GetViewProjection(Camera camera)
{
    // flip y axis because SpriteBatch drawing coordinates start from the top-left corner
    //   where positive x is right (same as FRB) and positive y is down (opposite of FRB)
    var adjustedView = camera.View with { M42 = -camera.View.M42 };
    var adjustedProj = camera.Projection with { M22 = -camera.Projection.M22 };

    return adjustedView * adjustedProj;
}

private static void SetCommonShaderParameters(Effect shader, Camera camera, Vector2 drawPosition, TimeSpan effectDuration, float textureScale, Texture2D texture)
{
    double normalizedTime = TimeManager.CurrentScreenTime % effectDuration.TotalSeconds / effectDuration.TotalSeconds;

    // ======= required parameters =======
    shader.Parameters["ViewProjection"].SetValue(GetViewProjection(camera));

    // ======= optional parameters =======
    shader.Parameters?["WorldPosition"]?.SetValue(drawPosition);
    shader.Parameters?["Time"]?.SetValue((float)TimeManager.CurrentScreenTime);
    shader.Parameters?["NormalizedTime"]?.SetValue((float)normalizedTime);
    shader.Parameters?["TextureSize"]?.SetValue(textureScale * new Vector2(texture.Width, texture.Height));
}
#if OPENGL
#define VS_SHADERMODEL vs_3_0
#define PS_SHADERMODEL ps_3_0
#else
#define VS_SHADERMODEL vs_4_0
#define PS_SHADERMODEL ps_4_0
#endif

//==============================================================================
// GraphicsDevice Parameters
//==============================================================================
SamplerState SamplerState0 : register(s0);

//==============================================================================
// External Parameters
//==============================================================================
float4x4 ViewProjection;
float Time;
float NormalizedTime;
float2 WorldPosition;
float2 TextureSize;

//==============================================================================
// Shader Stage Parameters
//==============================================================================
struct AssemblerToVertex
{
    float4 Position : POSITION0;
    float4 Color : COLOR0;
    float4 TexCoord : TEXCOORD0;
};

struct VertexToPixel
{
    float4 Position : SV_Position0;
    float4 Color : COLOR0;
    float4 TexCoord : TEXCOORD0;
};

//==============================================================================
// Vertex Shaders
//==============================================================================
VertexToPixel VsMain(const in AssemblerToVertex input)
{
    VertexToPixel output;

    output.Position = mul(input.Position, ViewProjection);
    output.Color = input.Color;
    output.TexCoord = input.TexCoord;

    return output;
}

//==============================================================================
// Pixel Shaders
//==============================================================================
float4 PsMain(VertexToPixel input) : SV_TARGET
{
    float4 diffuse = tex2D(SamplerState0, input.TexCoord.xy);
    float4 finalColor = diffuse * input.Color;

    return finalColor;
}

//==============================================================================
// Techniques
//==============================================================================
technique Tech0
{
    pass Pass0
    {
        VertexShader = compile VS_SHADERMODEL VsMain();
        PixelShader = compile PS_SHADERMODEL PsMain();
    }
}
treesgobark commented 1 year ago

TestTexture

vchelaru commented 1 day ago

This is going to be accompanied with changes to the engine and Glue to make adding global shaders easier. This may also expand to support layer-specific shaders/swap chains.

vchelaru commented 1 day ago

Adding a checklist of things to fix: