summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Bitmap.cs82
-rw-r--r--EmbeddedResources.cs5
-rw-r--r--Extensions.cs29
-rw-r--r--Main.cs30
-rw-r--r--Mouse.cs4
-rw-r--r--NetClient.cs1
-rw-r--r--Oneko.cs12
-rw-r--r--OnekoOnline.csproj1
8 files changed, 107 insertions, 57 deletions
diff --git a/Bitmap.cs b/Bitmap.cs
index fc6fa40..6922fae 100644
--- a/Bitmap.cs
+++ b/Bitmap.cs
@@ -25,23 +25,19 @@ class Bitmap : IDisposable
Texture = Raylib.LoadTextureFromImage(img);
- //Get Data for Serialization
- int imgSize = Raylib.GetPixelDataSize(img.Width, img.Height, PixelFormat.UncompressedR8G8B8A8);
- Span<byte> imgData;
- unsafe {
- imgData = new(img.Data, imgSize);
- }
- using MemoryStream stream = new();
+ //Write image info before compressed data
+ Span<byte> TexInfo = stackalloc byte[6];
+ BinaryPrimitives.WriteInt16LittleEndian(TexInfo, (short)Width);
+ BinaryPrimitives.WriteInt16LittleEndian(TexInfo[2..], (short)Height);
+ TexInfo[4] = (byte)img.Format;
+ TexInfo[5] = (byte)img.Mipmaps;
- //Write width and height before compressed data
- Span<byte> WidthHeight = stackalloc byte[4];
- BinaryPrimitives.WriteInt16LittleEndian(WidthHeight, (short)Width);
- BinaryPrimitives.WriteInt16LittleEndian(WidthHeight[2..], (short)Height);
- stream.Write(WidthHeight);
+ using MemoryStream stream = new();
+ stream.Write(TexInfo);
- using DeflateStream compressor = new(stream, CompressionLevel.Optimal);
- compressor.Write(imgData);
- compressor.Close();
+ DeflateStream compressor = new(stream, CompressionLevel.Optimal);
+ compressor.Write(img.DataSpan());
+ compressor.Dispose();
SerializedData = stream.ToArray();
Raylib.UnloadImage(img);
@@ -53,54 +49,58 @@ class Bitmap : IDisposable
Texture = tex;
}
+ public Bitmap Copy()
+ {
+ Image ImgCopy = Raylib.LoadImageFromTexture(Texture);
+ Bitmap Copy = new(Raylib.LoadTextureFromImage(ImgCopy), SerializedData.ToArray());
+ Raylib.UnloadImage(ImgCopy);
+ return Copy;
+ }
+
public static Bitmap FromFile(string path, int MaxW = MaxWidth, int MaxH = MaxHeight)
{
if (!File.Exists(path) || new FileInfo(path).Length > 40000 || !path.Contains(".png"))
return new Bitmap(Raylib.GenImageChecked(32, 32, 4, 4, Color.Black, Color.Pink));
- return new Bitmap(Raylib.LoadImage(path), MaxW, MaxH);
+ return new Bitmap(Raylib.LoadImageFromMemory(".png", File.ReadAllBytes(path)), MaxW, MaxH);
}
- public static Bitmap FromPNGMemory(byte[] memory, int MaxW = MaxWidth, int MaxH = MaxHeight)
- {
- return new Bitmap(Raylib.LoadImageFromMemory(".png", memory), MaxW, MaxH);
- }
+ public static Bitmap FromPNGMemory(byte[] memory, int MaxW = MaxWidth, int MaxH = MaxHeight) => new(Raylib.LoadImageFromMemory(".png", memory), MaxW, MaxH);
- public static Bitmap Deserialize(ReadOnlySpan<byte> span, int MaxW = MaxWidth, int MaxH = MaxHeight, byte[]? fallbackImage = null)
+ public static Bitmap Deserialize(ReadOnlySpan<byte> span, int MaxW = MaxWidth, int MaxH = MaxHeight, Image? fallbackImage = null)
{
int width = BinaryPrimitives.ReadInt16LittleEndian(span[..2]);
int height = BinaryPrimitives.ReadInt16LittleEndian(span.Slice(2, 2));
+ PixelFormat format = (PixelFormat)span[4];
+ int mipmaps = span[5];
- bool Invalid = width <=0 || height <= 0 || width > MaxW || height > MaxH;
- width = Math.Clamp(width, 1, MaxW);
- height = Math.Clamp(height, 1, MaxH);
+ bool Invalid = width <= 0 || height <= 0 || width > MaxW || height > MaxH || format != PixelFormat.UncompressedR8G8B8A8;
- //If the width and height are somehow wrong, then no use in loading the rest.
- if (Invalid && fallbackImage != null) return FromPNGMemory(fallbackImage, MaxW, MaxH);
- Image img = Raylib.GenImageChecked(width, height, 4, 4, Color.Pink, Color.Black);
- Raylib.ImageFormat(ref img, PixelFormat.UncompressedR8G8B8A8);
+ //If the is somehow invalid, then no use in loading the rest. Either use fallback, or generate error checkerboard.
+ if (Invalid && fallbackImage != null) return new Bitmap(Raylib.ImageCopy(fallbackImage.Value), MaxW, MaxH);
+ Image img = Raylib.GenImageChecked(Math.Clamp(width, 8, MaxW), Math.Clamp(height, 8, MaxH), 4, 4, Color.Pink, Color.Black);
if (Invalid) return new Bitmap(img);
- byte[] compressed = span[4..].ToArray();
- byte[] data = new byte[Raylib.GetPixelDataSize(width, height, PixelFormat.UncompressedR8G8B8A8)];
+ byte[] compressed = span[6..].ToArray();
+ byte[] data = new byte[RaylibExt.TextureLength(width, height, format, mipmaps)];
{
using MemoryStream input = new(compressed);
using DeflateStream decompressor = new(input, CompressionMode.Decompress);
decompressor.ReadExactly(data);
}
-
- Texture2D tex = Raylib.LoadTextureFromImage(img);
- Raylib.UpdateTexture(tex, data);
-
- Raylib.UnloadImage(img);
-
- return new Bitmap(tex, compressed);
+ unsafe {fixed (void* dataPtr = data) {
+ Texture2D tex = new() {
+ Id = Rlgl.LoadTexture(dataPtr, width, height, format, mipmaps),
+ Width = width,
+ Height = height,
+ Format = format,
+ Mipmaps = mipmaps
+ };
+ return new Bitmap(tex, compressed);
+ }}
}
- public byte[] Serialize()
- {
- return SerializedData;
- }
+ public byte[] Serialize() => SerializedData;
bool disposed = false;
diff --git a/EmbeddedResources.cs b/EmbeddedResources.cs
index 8fdc1f8..2be42a6 100644
--- a/EmbeddedResources.cs
+++ b/EmbeddedResources.cs
@@ -10,7 +10,8 @@ static class EmbeddedResources
public static byte[] GetResource(string name)
{
using Stream EmbeddedFile = assembly.GetManifestResourceStream($"{assemblyName}.{name}")!;
- using BinaryReader reader = new(EmbeddedFile);
- return reader.ReadBytes((int)EmbeddedFile.Length);
+ byte[] fileData = new byte[EmbeddedFile.Length];
+ EmbeddedFile.ReadExactly(fileData);
+ return fileData;
}
} \ No newline at end of file
diff --git a/Extensions.cs b/Extensions.cs
index e6368c3..80a8e2f 100644
--- a/Extensions.cs
+++ b/Extensions.cs
@@ -1,8 +1,9 @@
using System.Numerics;
+using Raylib_cs;
namespace OnekoOnline;
-static class MathExtensions
+static class MathExt
{
public static Vector2 LimitLength(this Vector2 toLimit, float lengthLimit)
{
@@ -17,7 +18,7 @@ static class MathExtensions
}
}
-static class StringExtensions
+static class StringExt
{
public static string LimitLength(this string value, int maxLength)
{
@@ -26,6 +27,30 @@ static class StringExtensions
}
}
+static class RaylibExt
+{
+ public static int TextureLength(int width, int height, PixelFormat format, int mipmaps)
+ {
+ int size = 0;
+
+ for (int i = 0; i < mipmaps; i++) {
+ size += Raylib.GetPixelDataSize(width, height, format);
+
+ //Max is a security check for NPOT textures
+ width = Math.Max(width/2, 1);
+ height = Math.Max(height/2, 1);
+ }
+
+ return size;
+ }
+
+ public static int DataLength(this Image img) => TextureLength(img.Width, img.Height, img.Format, img.Mipmaps);
+
+ public static int DataLength(this Texture2D tex) => TextureLength(tex.Width, tex.Height, tex.Format, tex.Mipmaps);
+
+ public unsafe static Span<byte> DataSpan(this Image img) => new(img.Data, img.DataLength());
+}
+
public static class Directions
{
public static readonly Vector2 Up = new(0,-1);
diff --git a/Main.cs b/Main.cs
index b1793fd..99a313f 100644
--- a/Main.cs
+++ b/Main.cs
@@ -16,15 +16,24 @@ static class OnekoOnline
public static Vector2 Resolution => new(WindowX, WindowY);
public static readonly bool SpectatorMode = Config.GetValue("SpectatorMode", false);
+ public static readonly bool HostServer = Config.GetValue("HostServer", false);
+ public static readonly bool TransparentWindow = Config.GetValue("TransparentWindow", false);
public static Font DefaultFont;
- const ConfigFlags raylibConfFlags = ConfigFlags.VSyncHint;
+ public static string AppTitle {
+ get => _appTitle;
+ set {
+ Raylib.SetWindowTitle(value);
+ _appTitle = value;
+ }
+ }
+ static string _appTitle = "Oneko Online";
public static void Main()
{
- Raylib.SetConfigFlags(raylibConfFlags);
- Raylib.InitWindow(WindowX*WindowScale, WindowY*WindowScale, "OnekoOnline");
+ if (TransparentWindow) Raylib.SetConfigFlags(ConfigFlags.TransparentWindow);
+ Raylib.InitWindow(WindowX*WindowScale, WindowY*WindowScale, AppTitle);
Raylib.SetTargetFPS(30);
Raylib.HideCursor();
@@ -36,13 +45,16 @@ static class OnekoOnline
int port = Config.GetValue("ServerPort", 42069);
string serverPassword = Config.GetValue("ServerPassword", "");
- if (Config.GetValue("HostServer", false)) {
+ if (HostServer) {
Server = new(port, Config.GetValue("ServerMaxUsers", 32));
Client = new("127.0.0.1", port, serverPassword);
} else {
string Address = Config.GetValue("ServerIP", "pond.sarahduck.ca");
- if (string.IsNullOrEmpty(Address)) Console.WriteLine("Server IP empty or invalid, you're offline.");
+ if (string.IsNullOrEmpty(Address)) {
+ Console.WriteLine("Server IP empty or invalid, you're offline.");
+ AppTitle = "Oneko Offline";
+ }
else Client = new(Address, port, serverPassword);
}
Net.Client.UserConnected += OnekoNet.SpawnNetNeko;
@@ -50,6 +62,9 @@ static class OnekoOnline
DefaultFont = Raylib.LoadFont("misc/MPlusBitmap.fnt");
+ Color BackgroundColor = Color.Gray;
+ if (TransparentWindow) BackgroundColor = BackgroundColor with {A = 0};
+
while (!Raylib.WindowShouldClose())
{
//Poll networking
@@ -58,15 +73,16 @@ static class OnekoOnline
Raylib.BeginTextureMode(RenderTexture);
- Raylib.ClearBackground(Color.Gray);
+ Raylib.ClearBackground(BackgroundColor);
Raylib.DrawTextEx(DefaultFont, "こんにちは", new(17,18), 11, 0, Color.White);
- Raylib.DrawText("Oneko Online", 10, 9, 8, Color.White);
+ Raylib.DrawText(AppTitle, 10, 9, 8, Color.White);
Drawable.DrawAll();
Raylib.EndTextureMode();
Raylib.BeginDrawing();
+ if (TransparentWindow) Raylib.ClearBackground(Color.Blank);
//Dunno why, but it renders upside down, so I flip it here
Raylib.DrawTexturePro(RenderTexture.Texture, new Rectangle(0f,0f,WindowX,-WindowY), new Rectangle(0,0,WindowX*WindowScale,WindowY*WindowScale), Vector2.Zero,0f,Color.White);
Raylib.EndDrawing();
diff --git a/Mouse.cs b/Mouse.cs
index fdf0c5c..67356ce 100644
--- a/Mouse.cs
+++ b/Mouse.cs
@@ -15,7 +15,7 @@ abstract class Mouse : Drawable
public static Action<Mouse>? Clicked;
- protected readonly static byte[] FallbackImg = EmbeddedResources.GetResource("misc.cursor.png");
+ protected readonly static Image FallbackImg = Raylib.LoadImageFromMemory(".png", EmbeddedResources.GetResource("misc.cursor.png"));
public Mouse() : base()
{
@@ -28,7 +28,7 @@ abstract class Mouse : Drawable
Cursor = Bitmap.FromPNGMemory(File.ReadAllBytes(CursorPath), 32, 32);
} else {
Console.WriteLine("The cursor PNG was either mising or too big. Using the default.");
- Cursor = Bitmap.FromPNGMemory(FallbackImg);
+ Cursor = new Bitmap(Raylib.ImageCopy(FallbackImg), 32, 32);
}
}
diff --git a/NetClient.cs b/NetClient.cs
index ce70d91..db62337 100644
--- a/NetClient.cs
+++ b/NetClient.cs
@@ -59,6 +59,7 @@ class Client
ServerDisconnected?.Invoke();
users.Clear();
Console.WriteLine("Server Disconnected! You're offline!");
+ OnekoOnline.AppTitle = "Oneko Offline";
};
Listener.NetworkReceiveEvent += (fromPeer, reader, channel, DeliveryMethod) => {
diff --git a/Oneko.cs b/Oneko.cs
index e63c56a..402cc73 100644
--- a/Oneko.cs
+++ b/Oneko.cs
@@ -20,7 +20,7 @@ abstract class Oneko : Drawable
protected static List<Oneko> allNekos = [];
public static ReadOnlyCollection<Oneko> AllNekos => allNekos.AsReadOnly();
- protected readonly static byte[] FallbackImg = EmbeddedResources.GetResource("nekos.oneko.png");
+ protected readonly static Image FallbackImg = Raylib.LoadImageFromMemory(".png", EmbeddedResources.GetResource("nekos.oneko.png"));
public Oneko() : base()
{
@@ -30,10 +30,16 @@ abstract class Oneko : Drawable
string SpriteSheetPath = OnekoOnline.Config.GetValue("SpriteSheetPath", "nekos/oneko.png");
if (File.Exists(SpriteSheetPath) && new FileInfo(SpriteSheetPath).Length < 128*256*3) {
- SpriteSheet = Bitmap.FromPNGMemory(File.ReadAllBytes(SpriteSheetPath), 256, 128);
+ #if DEBUG
+ //Bitmap Serialization test
+ using Bitmap SerializeTest = Bitmap.FromPNGMemory(File.ReadAllBytes(SpriteSheetPath), 256, 128);
+ SpriteSheet = Bitmap.Deserialize(SerializeTest.Serialize());
+ #else
+ SpriteSheet = Bitmap.FromPNGMemory(File.ReadAllBytes(SpriteSheetPath), 256, 128);
+ #endif
} else {
Console.WriteLine("Path to spritesheet was invalid or the file was too big, using the default.");
- SpriteSheet = Bitmap.FromPNGMemory(FallbackImg, 256, 128);
+ SpriteSheet = new Bitmap(Raylib.ImageCopy(FallbackImg), 256, 128);
}
allNekos.Add(this);
diff --git a/OnekoOnline.csproj b/OnekoOnline.csproj
index c0eb221..190e234 100644
--- a/OnekoOnline.csproj
+++ b/OnekoOnline.csproj
@@ -10,6 +10,7 @@
<PublishAot>true</PublishAot>
<StripSymbols>true</StripSymbols>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
+ <InvariantGlobalization>true</InvariantGlobalization>
</PropertyGroup>