Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

LoadShaderFromMemory Function is not working. #20

Closed
SoloByte opened this issue Jul 25, 2022 · 9 comments
Closed

LoadShaderFromMemory Function is not working. #20

SoloByte opened this issue Jul 25, 2022 · 9 comments

Comments

@SoloByte
Copy link

Using LoadShaderFromMemory returns a shader but when used in Raylib.BeginShaderMode(shader); the shader does not work. Doing the exact same thing in a project using Raylib cs everything works as expected.

Does the first try-statement throw an exception if "vsCode" parameter is null?

Raylib CsLo Binding Code:

public unsafe static Shader LoadShaderFromMemory(string? vsCode, string fsCode)
{
    SpanOwner<sbyte> spanOwner = vsCode.MarshalUtf8();
    try
    {
        SpanOwner<sbyte> spanOwner2 = fsCode.MarshalUtf8();
        try
        {
            return LoadShaderFromMemory(spanOwner.AsPtr(), spanOwner2.AsPtr());
        }
        finally
        {
            spanOwner2.Dispose();
        }
    }
    finally
    {
        spanOwner.Dispose();
    }
}

Raylib Cs Binding Code:

public unsafe static Shader LoadShaderFromMemory(string vsCode, string fsCode)
{
    using UTF8Buffer uTF8Buffer = vsCode.ToUTF8Buffer();
    using UTF8Buffer uTF8Buffer2 = fsCode.ToUTF8Buffer();
    return LoadShaderFromMemory(uTF8Buffer.AsPointer(), uTF8Buffer2.AsPointer());
}
@jasonswearingen
Copy link
Member

I think you are right about the vsCode being null. Do you have an example I could add to the Samples, to test/verify?

@SoloByte
Copy link
Author

SoloByte commented Sep 6, 2022

What would that example look like? Do you just need a visual studio project with minimal code to reproduce the issue?

@jasonswearingen
Copy link
Member

a project would work, but even something like a code snippet would be fine, as long as it would obviously "work" if the bug is fixed?

FYI this weekend I"m going to setup my Raylib dev env again, to do the 4.2 port and so will be looking at this then.

@SoloByte
Copy link
Author

SoloByte commented Sep 9, 2022

@jasonswearingen I have a minimal project to show the problem. For now, I am posting the code here, if that is too cumbersome for you just tell me how to send it to you ;)

-----Program.cs file------

using Raylib_CsLo;
using System.Text;
using System.IO.Compression;

namespace LoadShaderFromMemoryTest
{
    public static class ResourceManager
    {
        internal struct ResourceInfo
        {
            public string extension;
            public byte[] data;

            public ResourceInfo(string extension, byte[] data) { this.extension = extension; this.data = data; }
        }


        //private static List<string> generatedLines = new();
        private static Dictionary<string, ResourceInfo> resources = new();

        public static void Initialize()
        {
            resources = LoadResources(Generate("shaders"));
        }
        public static void Close()
        {
            resources.Clear();
        }

        public static Shader LoadFragmentShader(string name)
        {
            if (Path.HasExtension(name)) return Raylib.LoadShader(null, name);
            else
            {
                string file = Encoding.Default.GetString(resources[name].data);
                return Raylib.LoadShaderFromMemory(null, file);
            }
        }
        private static List<string> Generate(string sourcePath)
        {
            string[] files = Directory.GetFiles(sourcePath, "", SearchOption.AllDirectories);
            List<string> lines = new List<string>();
            foreach (var file in files)
            {
                lines.Add(Path.GetFileName(file));
                var d = File.ReadAllBytes(file);
                lines.Add(Convert.ToBase64String(Compress(d)));
            }
            return lines;
        }
        private static Dictionary<string, ResourceInfo> LoadResources(List<string> lines)
        {
            Dictionary<string, ResourceInfo> result = new();
            for (int i = 0; i < lines.Count; i += 2)
            {
                string filenName = lines[i];
                string name = Path.GetFileNameWithoutExtension(filenName);
                string extension = Path.GetExtension(filenName);
                string dataText = lines[i + 1];
                var data = Convert.FromBase64String(dataText);
                result.Add(name, new(extension, Decompress(data)));
            }
            return result;
        }

        private static byte[] Compress(byte[] data)
        {
            MemoryStream output = new MemoryStream();
            using (DeflateStream dstream = new DeflateStream(output, CompressionLevel.Optimal))
            {
                dstream.Write(data, 0, data.Length);
            }
            return output.ToArray();
        }
        private static byte[] Decompress(byte[] data)
        {
            MemoryStream input = new MemoryStream(data);
            MemoryStream output = new MemoryStream();
            using (DeflateStream dstream = new DeflateStream(input, CompressionMode.Decompress))
            {
                dstream.CopyTo(output);
            }
            return output.ToArray();
        }
    }


    public class Program
    {
        const int GLSL_VERSION = 330;

        static void Main(string[] args)
        {
            // Initialization
            //--------------------------------------------------------------------------------------
            const int screenWidth = 800;
            const int screenHeight = 450;

            Raylib.InitWindow(screenWidth, screenHeight, "Load Shader From Memory Test");

            Image imBlank = Raylib.GenImageColor(1024, 1024, Raylib.BLANK);
            Texture texture = Raylib.LoadTextureFromImage(imBlank);  // Load blank texture to fill on shader
            Raylib.UnloadImage(imBlank);

            ResourceManager.Initialize();
            
            Shader shaderFromFile = Raylib.LoadShader(null, "shaders/cubes-panning.fs");
            Shader shaderFromMemory = ResourceManager.LoadFragmentShader("cubes-panning");
            Shader currentShader = shaderFromFile;
            int currentShaderIndex = 0;

            float time = 0.0f;
            int timeLoc = Raylib.GetShaderLocation(shaderFromFile, "uTime");
            Raylib.SetShaderValue(shaderFromFile, timeLoc, time, ShaderUniformDataType.SHADER_UNIFORM_FLOAT);
            Raylib.SetShaderValue(shaderFromMemory, timeLoc, time, ShaderUniformDataType.SHADER_UNIFORM_FLOAT);

            Raylib.SetTargetFPS(60); // Set our game to run at 60 frames-per-second
            // -------------------------------------------------------------------------------------------------------------

            // Main game loop
            while (!Raylib.WindowShouldClose()) // Detect window close button or ESC key
            {

                //toggle between the shader loaded from memory and the shader loaded from file
                if (Raylib.IsKeyPressed(KeyboardKey.KEY_SPACE))
                {
                    if (currentShaderIndex == 0)
                    {
                        currentShader = shaderFromMemory;
                        currentShaderIndex = 1;
                    }
                    else
                    {
                        currentShader = shaderFromFile;
                        currentShaderIndex = 0;
                    }

                }

                // Update
                //----------------------------------------------------------------------------------
                time = (float)Raylib.GetTime();
                Raylib.SetShaderValue(currentShader, timeLoc, time, ShaderUniformDataType.SHADER_UNIFORM_FLOAT);
                //----------------------------------------------------------------------------------

                // Draw
                //----------------------------------------------------------------------------------
                Raylib.BeginDrawing();
                Raylib.ClearBackground(Raylib.RAYWHITE);

                Raylib.BeginShaderMode(currentShader);    // Enable our custom shader for next shapes/textures drawings
                Raylib.DrawTexture(texture, 0, 0, Raylib.WHITE);  // Drawing BLANK texture, all magic happens on shader
                Raylib.EndShaderMode();            // Disable our custom shader, return to default shader

                Raylib.DrawRectangleV(new(0), new(screenWidth, 100), new(0, 0, 0, 210));
                Raylib.DrawText("BACKGROUND is PAINTED and ANIMATED on SHADER!", 10, 10, 20, Raylib.MAROON);
                if (currentShaderIndex == 0)
                {
                    Raylib.DrawText("Shader From File Active", 10, 38, 40, Raylib.BLUE);
                }
                else
                {
                    Raylib.DrawText("Shader From Memory Active", 10, 38, 40, Raylib.BLUE);
                }
                Raylib.DrawText("[SPACE] - Cycle Shaders", 10, 76, 20, Raylib.BLUE);
               

                Raylib.EndDrawing();
                //----------------------------------------------------------------------------------
            }

            // De-Initialization
            //--------------------------------------------------------------------------------------
            Raylib.UnloadShader(currentShader);

            Raylib.CloseWindow();        // Close window and OpenGL context
            //--------------------------------------------------------------------------------------

        }
        
    }

}

Create a folder called shaders and put the shader in it.
------ cubes-panning.fs -----

#version 330

// Input vertex attributes (from vertex shader)
in vec2 fragTexCoord;
in vec4 fragColor;

// Output fragment color
out vec4 finalColor;

// Custom variables
#define PI 3.14159265358979323846
uniform float uTime = 0.0;

float divisions = 5.0;
float angle = 0.0;

vec2 VectorRotateTime(vec2 v, float speed)
{
    float time = uTime*speed;
    float localTime = fract(time);  // The time domain this works on is 1 sec.

    if ((localTime >= 0.0) && (localTime < 0.25)) angle = 0.0;
    else if ((localTime >= 0.25) && (localTime < 0.50)) angle = PI/4*sin(2*PI*localTime - PI/2);
    else if ((localTime >= 0.50) && (localTime < 0.75)) angle = PI*0.25;
    else if ((localTime >= 0.75) && (localTime < 1.00)) angle = PI/4*sin(2*PI*localTime);

    // Rotate vector by angle
    v -= 0.5;
    v =  mat2(cos(angle), -sin(angle), sin(angle), cos(angle))*v;
    v += 0.5;

    return v;
}

float Rectangle(in vec2 st, in float size, in float fill)
{
  float roundSize = 0.5 - size/2.0;
  float left = step(roundSize, st.x);
  float top = step(roundSize, st.y);
  float bottom = step(roundSize, 1.0 - st.y);
  float right = step(roundSize, 1.0 - st.x);

  return (left*bottom*right*top)*fill;
}

void main()
{
    vec2 fragPos = fragTexCoord;
    fragPos.xy += uTime/9.0;

    fragPos *= divisions;
    vec2 ipos = floor(fragPos);  // Get the integer coords
    vec2 fpos = fract(fragPos);  // Get the fractional coords

    fpos = VectorRotateTime(fpos, 0.2);

    float alpha = Rectangle(fpos, 0.216, 1.0);
    vec3 color = vec3(0.3, 0.3, 0.3);

    finalColor = vec4(color, alpha);
}

In case you want to see it.
----- .csproj file -----

<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
    <OutputType>WinExe</OutputType>
    <TargetFramework>net6.0</TargetFramework>
    <ImplicitUsings>enable</ImplicitUsings>
    <Nullable>enable</Nullable>
	<RunWorkingDirectory>$(MSBuildThisFileDirectory)</RunWorkingDirectory>
  </PropertyGroup>

  <ItemGroup>
    <PackageReference Include="Raylib-CsLo" Version="4.0.1" />
  </ItemGroup>

</Project>

@CodingMadness
Copy link

Was this bug fixed by now?

@jasonswearingen
Copy link
Member

I am finished updating to raylib 4.2 and looking at this now. am I correct that the failure case is that when hitting spacebar, so that "Shader from memory active" is selected, the screen is blank?

and that the success case would it show the same shader as loaded from file?

@jasonswearingen
Copy link
Member

yes I think that is it. I fixed the problem, and will close this after I upload the nuget package. are you on windows or another platform?

@jasonswearingen
Copy link
Member

4.2.0alpha1 is on nuget now.

@SoloByte
Copy link
Author

@jasonswearingen I am on windows. It seems to work correctly now! Thanks :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants