Closed SoloByte closed 2 years ago
Hi, could you tell me the steps currently needed to use this? I just briefly skimmed, and it looks like I would need to make a wrapper over rres.h from here: https://github.com/raysan5/rres
This is totally doable, and very easy to do so by anybody using the scripts found in CsLo. However I am currently remote for the next MONTH so not near my gamedev machine where I do this sort of work. Could you please confirm that it's rres.h that needs to be wrapped, and any other details? I can take a look when I get back (End of Aug) or in the meantime, if you want to checkin rres.h and modify the build script to include it in the CsLo output I'd be happy to merge. If this seems interesting, see https://github.com/NotNotTech/Raylib-CsLo/tree/main/sub-modules
Hi! Thanks for getting back to me. As I understand it "rres.h" and "rres-raylib.h" need to be wrapped. Rres-raylib.h is needed to convert the packed data into usably data structures for raylib. It is described here and here.
It is not urgent so take your time. I found a temporary solution that works for me until rres is ready. Unfortunately, I don´t know much about the process of creating bindings, so I am afraid I can´t help you there.
This is my temporary solution for packing resources into 1 file to make the distribution of the build easier. For anyone looking for something like this feel free to use it any way you want.
LoadShaderFromMemory
is not working (see #20) so when using the resource manager you can not load shaders right now. As soon as it is fixed loading shaders with the resource manager will work without any changes.I always set this in my project file:
<RunWorkingDirectory>$(MSBuildThisFileDirectory)</RunWorkingDirectory>
to make the paths relative to the project.
You need a single folder containing all the resources you want to pack. I mostly just have a resources folder with a structure like that in my project:
resources -gfx --exampe-texture.png -audio --sfx ---example-sound.wav --music ---example-music.ogg -fonts --example-font.ttf -shaders --example-shader.fs
string sourcePath = "resources"; //because it is relative to the project that is enough
string outputPath = ""; //empty path puts it in the root of your project and the file is always called resources.txt
ResourceManager.Generate(sourcePath, outputPath);
And when you run the game in visual studio the file is created.
When you build the game and you want to launch it from the .exe file make sure to comment out the ResourceManager.Generate(sourcePath, outputPath)
Function Call!
Additionally, you can right-click on the newly created resources.txt in visual studio, go to properties, and set "Copy To Output Directory" to "Always Copy" so the file is copied to the output directory when you build the game.
You could make a separate console app with the source code and use the .exe file in a pre-build event in visual studio to automate the process of packing the resources.
You need to create an instance of the ResourceManager Class and give it the path to the resources.txt file. After that just call any of the Load Functions in the resource manager instance to load resources (Image, Texture, Font, Sound, Music, Shader, Json String).
var resourceManager = new ResourceManager(""); //because file is in the root of the project "" is enough
var texture = resourceManager.LoadTexture("example-texture");
var sound = resourceManager.LoadSound("example-sound");
var music = resourceManager.LoadMusic("example-music");
var font = resourceManager.LoadFont("example-font", 100);
var shader = resourceManager.LoadFragmentShader("example-shader");
using Raylib_CsLo;
using System.Text;
using System.IO.Compression;
namespace Resources
{
//shader loading does not work yet
internal struct ResourceInfo
{
public string extension;
public byte[] data;
public ResourceInfo(string extension, byte[] data) { this.extension = extension; this.data = data; }
}
public static class ResourceManager
{
private static Dictionary<string, ResourceInfo> resources = new();
public static void Initialize(string path)
{
resources = LoadResources(path);
}
public static void Generate(string sourcePath, string outputPath)
{
string filename = "resources.txt";
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)));
}
File.WriteAllLines(outputPath + filename, lines);
}
public static Texture LoadTexture(string name)
{
return Raylib.LoadTextureFromImage(LoadImage(name));
}
public static Image LoadImage(string name)
{
unsafe
{
var data = resources[name].data;
var extension = resources[name].extension;
fixed (byte* ptr = data)
{
return Raylib.LoadImageFromMemory(extension, ptr, data.Length);
}
}
}
public static Font LoadFont(string name, int fontSize = 100)
{
unsafe
{
var data = resources[name].data;
var extension = resources[name].extension;
fixed (byte* ptr = data)
{
return Raylib.LoadFontFromMemory(extension, ptr, data.Length, fontSize, (int*)0, 300);
}
}
}
public static Wave LoadWave(string name)
{
unsafe
{
var data = resources[name].data;
var extension = resources[name].extension;
fixed (byte* ptr = data)
{
return Raylib.LoadWaveFromMemory(extension, ptr, data.Length);
}
}
}
public static Sound LoadSound(string name)
{
return Raylib.LoadSoundFromWave(LoadWave(name));
}
public static Music LoadMusic(string name)
{
unsafe
{
var data = resources[name].data;
var extension = resources[name].extension;
fixed (byte* ptr = data)
{
return Raylib.LoadMusicStreamFromMemory(extension, ptr, data.Length);
}
}
}
public static Shader LoadFragmentShader(string name)
{
string file = Encoding.Default.GetString(resources[name].data);
return Raylib.LoadShaderFromMemory(null, file);
}
public static Shader LoadVertexShader(string name)
{
string file = Encoding.Default.GetString(resources[name].data);
return Raylib.LoadShaderFromMemory(null, file);
}
public static string LoadJsonData(string name)
{
return Encoding.Default.GetString(resources[name].data);
}
private static Dictionary<string, ResourceInfo> LoadResources(string path)
{
Dictionary<string, ResourceInfo> result = new();
var lines = File.ReadAllLines(path + "resources.txt");
for (int i = 0; i < lines.Length; 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();
}
}
}
sorry for the delay, I will try to create bindings for everything with the update to 4.2, this comming weekend.
No problem! Thank you very much ;)
I included basic (unsafe) bindings to RRes, but no tests for it. please let me know how, or if it works. will be in the alpha1 nuget in a few minutes.
@jasonswearingen Thank you very much! I will test it as soon as I can and let you know if everything works ;)
Issue description
Dealing with exported resources in raylib with c# is complicated right now.
The default way is to copy the resource folder to the output directory but when distributing your game/app all resources are visible to the customer. (among many other problems with that way)
The problem is that loading resources from anywhere else than the disk is very complicated or not possible. (to my knowledge with raylib c# bindings) So my only solution would be to compress/encrypt the resources when building and then uncompress/decrypt them when the game/app is started but then the resources are visible again to the user while the game/app is running.
Raysan already implemented a solution for raylib called rres but it is only available for c right now. The resource packer can already be used to pack all the resources into a rres file but there is no way to load that rres file and transform it into raylib types like image, font, wave, etc. right now.
It would be really nice if there would be separate bindings for rres so it can be used with c# and it would make raylib with c# much more robust.
PS: At least it would be nice to know if you are interested in doing that at all. Because I don´t need it right now and if you would like to do it I am not going to look for another solution.
I will also ask ChrisDill with raylib-cs bindings.
Thanks!