From af6b885751eafcfee60ad6f3600cb67f06451692 Mon Sep 17 00:00:00 2001 From: Alessandro Proto Date: Mon, 20 Feb 2023 22:18:42 +0100 Subject: [PATCH] Add ANSI charset to term --- Capy64/Assets/charset.png | Bin 0 -> 3324 bytes Capy64/Capy64.csproj | 6 +++ Capy64/Core/Charset.cs | 79 +++++++++++++++++++++++++++++++ Capy64/Core/Drawing.cs | 34 ++++++------- Capy64/Runtime/EventEmitter.cs | 3 +- Capy64/Runtime/Libraries/Term.cs | 37 ++++++++++----- 6 files changed, 129 insertions(+), 30 deletions(-) create mode 100644 Capy64/Assets/charset.png create mode 100644 Capy64/Core/Charset.cs diff --git a/Capy64/Assets/charset.png b/Capy64/Assets/charset.png new file mode 100644 index 0000000000000000000000000000000000000000..f966538aeedfa48ed5ad178f8f23d58c5933973c GIT binary patch literal 3324 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 + + PreserveNewest + PreserveNewest @@ -58,4 +61,7 @@ + + + \ No newline at end of file diff --git a/Capy64/Core/Charset.cs b/Capy64/Core/Charset.cs new file mode 100644 index 0000000..f86ab96 --- /dev/null +++ b/Capy64/Core/Charset.cs @@ -0,0 +1,79 @@ +// This file is part of Capy64 - https://github.com/Ale32bit/Capy64 +// Copyright 2023 Alessandro "AlexDevs" Proto +// +// Licensed under the Apache License', Version 2.0 (the "License"). +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing', software +// distributed under the License is distributed on an "AS IS" BASIS', +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND', either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +using Capy64.API; +using Microsoft.Xna.Framework; +using Microsoft.Xna.Framework.Graphics; +using System.Collections.Generic; + +namespace Capy64.Core; + +public class Charset : IComponent +{ + public static int CharWidth => 6; + public static int CharHeight => 12; + + public static readonly char[] Codepoints = new char[] + { + '\u0000', '\u263A', '\u263B', '\u2665', '\u2666', '\u2663', '\u2660', '\u2022', '\u25D8', '\u25CB', '\u25D9', '\u2642', '\u2640', '\u266A', '\u266B', '\u263C', + '\u25BA', '\u25C4', '\u2195', '\u203C', '\u00B6', '\u00A7', '\u25AC', '\u21A8', '\u2191', '\u2193', '\u2192', '\u2190', '\u221F', '\u2194', '\u25B2', '\u25BC', + '\u0020', '\u0021', '\u0022', '\u0023', '\u0024', '\u0025', '\u0026', '\u0027', '\u0028', '\u0029', '\u002A', '\u002B', '\u002C', '\u002D', '\u002E', '\u002F', + '\u0030', '\u0031', '\u0032', '\u0033', '\u0034', '\u0035', '\u0036', '\u0037', '\u0038', '\u0039', '\u003A', '\u003B', '\u003C', '\u003D', '\u003E', '\u003F', + '\u0040', '\u0041', '\u0042', '\u0043', '\u0044', '\u0045', '\u0046', '\u0047', '\u0048', '\u0049', '\u004A', '\u004B', '\u004C', '\u004D', '\u004E', '\u004F', + '\u0050', '\u0051', '\u0052', '\u0053', '\u0054', '\u0055', '\u0056', '\u0057', '\u0058', '\u0059', '\u005A', '\u005B', '\u005C', '\u005D', '\u005E', '\u005F', + '\u0060', '\u0061', '\u0062', '\u0063', '\u0064', '\u0065', '\u0066', '\u0067', '\u0068', '\u0069', '\u006A', '\u006B', '\u006C', '\u006D', '\u006E', '\u006F', + '\u0070', '\u0071', '\u0072', '\u0073', '\u0074', '\u0075', '\u0076', '\u0077', '\u0078', '\u0079', '\u007A', '\u007B', '\u007C', '\u007D', '\u007E', '\u2302', + '\u00C7', '\u00FC', '\u00E9', '\u00E2', '\u00E4', '\u00E0', '\u00E5', '\u00E7', '\u00EA', '\u00EB', '\u00E8', '\u00EF', '\u00EE', '\u00EC', '\u00C4', '\u00C5', + '\u00C9', '\u00E6', '\u00C6', '\u00F4', '\u00F6', '\u00F2', '\u00FB', '\u00F9', '\u00FF', '\u00D6', '\u00DC', '\u00A2', '\u00A3', '\u00A5', '\u20A7', '\u0192', + '\u00E1', '\u00ED', '\u00F3', '\u00FA', '\u00F1', '\u00D1', '\u00AA', '\u00BA', '\u00BF', '\u2310', '\u00AC', '\u00BD', '\u00BC', '\u00A1', '\u00AB', '\u00BB', + '\u2591', '\u2592', '\u2593', '\u2502', '\u2524', '\u2561', '\u2562', '\u2556', '\u2555', '\u2563', '\u2551', '\u2557', '\u255D', '\u255C', '\u255B', '\u2510', + '\u2514', '\u2534', '\u252C', '\u251C', '\u2500', '\u253C', '\u255E', '\u255F', '\u255A', '\u2554', '\u2569', '\u2566', '\u2560', '\u2550', '\u256C', '\u2567', + '\u2568', '\u2564', '\u2565', '\u2559', '\u2558', '\u2552', '\u2553', '\u256B', '\u256A', '\u2518', '\u250C', '\u2588', '\u2584', '\u258C', '\u2590', '\u2580', + '\u03B1', '\u00DF', '\u0393', '\u03C0', '\u03A3', '\u03C3', '\u00B5', '\u03C4', '\u03A6', '\u0398', '\u03A9', '\u03B4', '\u221E', '\u03C6', '\u03B5', '\u2229', + '\u2261', '\u00B1', '\u2265', '\u2264', '\u2320', '\u2321', '\u00F7', '\u2248', '\u00B0', '\u2219', '\u00B7', '\u221A', '\u207F', '\u00B2', '\u25A0', '\u00A0', + }; + public static Dictionary CharDict => _charMap; + public static Texture2D Source => _source; + public static Rectangle[] Coords => _coords; + + private static Dictionary _charMap = new(); + private static Texture2D _source; + private static Rectangle[] _coords = new Rectangle[Codepoints.Length]; + public Charset() + { + _source = Texture2D.FromFile(Capy64.Instance.GraphicsDevice, "Assets/charset.png"); + + for (int i = 0; i < Codepoints.Length; i++) + { + _coords[i] = new Rectangle + { + X = CharWidth * (i % 16), + Y = CharHeight * (i / 16), + Width = CharWidth, + Height = CharHeight, + }; + + _charMap[Codepoints[i]] = i; + } + } + + public static int GetIndex(char c) + { + if (_charMap.TryGetValue(c, out var index)) + return index; + + return _charMap['?']; + } +} diff --git a/Capy64/Core/Drawing.cs b/Capy64/Core/Drawing.cs index ce4e6ec..0367130 100644 --- a/Capy64/Core/Drawing.cs +++ b/Capy64/Core/Drawing.cs @@ -25,7 +25,7 @@ namespace Capy64.Core; public class Drawing : IDisposable { - private SpriteBatch _spriteBatch; + public SpriteBatch SpriteBatch; private GraphicsDevice _graphicsDevice; private readonly FontSystem _fontSystem; private Texture2D _whitePixel; @@ -41,10 +41,10 @@ public class Drawing : IDisposable if (isDrawing) End(); _canvas = value; - _spriteBatch = new SpriteBatch(_canvas.GraphicsDevice); + SpriteBatch = new SpriteBatch(_canvas.GraphicsDevice); _graphicsDevice = _canvas.GraphicsDevice; - _whitePixel = new Texture2D(_spriteBatch.GraphicsDevice, 1, 1, mipmap: false, SurfaceFormat.Color); + _whitePixel = new Texture2D(SpriteBatch.GraphicsDevice, 1, 1, mipmap: false, SurfaceFormat.Color); _whitePixel.SetData(new Color[1] { Color.White }); if (isDrawing) Begin(); @@ -65,7 +65,7 @@ public class Drawing : IDisposable _isDrawing = true; _graphicsDevice.SetRenderTarget(_canvas); _graphicsDevice.DepthStencilState = new DepthStencilState() { DepthBufferEnable = true, }; - _spriteBatch.Begin(); + SpriteBatch.Begin(); } public void End() @@ -73,7 +73,7 @@ public class Drawing : IDisposable if (!_isDrawing) return; - _spriteBatch.End(); + SpriteBatch.End(); _graphicsDevice.SetRenderTarget(null); foreach (var t in _disposeTextures) @@ -86,7 +86,7 @@ public class Drawing : IDisposable public void DrawString(Vector2 pos, string text, Color color, int size = 13) { var font = _fontSystem.GetFont(size); - _spriteBatch.DrawString(font, text, pos, color, layerDepth: 0); + SpriteBatch.DrawString(font, text, pos, color, layerDepth: 0); } public Vector2 MeasureString(string text, int size = 13) @@ -151,18 +151,18 @@ public class Drawing : IDisposable public void DrawPoint(Vector2 point, Color color, int size = 1) { - _spriteBatch.DrawPoint(point, color, size); + SpriteBatch.DrawPoint(point, color, size); } public void DrawCircle(Vector2 pos, int radius, Color color, int thickness = 1, int sides = -1) { sides = sides < 0 ? radius * 4 : sides; - _spriteBatch.DrawCircle(pos, radius, sides, color, thickness); + SpriteBatch.DrawCircle(pos, radius, sides, color, thickness); } public void DrawLine(Vector2 start, Vector2 end, Color color, float thickness = 1) { - _spriteBatch.DrawLine(start, end, color, thickness); + SpriteBatch.DrawLine(start, end, color, thickness); } public void DrawRectangle(Vector2 pos, Size2 size, Color color, int thickness = 1, float rotation = 0f) @@ -172,13 +172,13 @@ public class Drawing : IDisposable public void DrawPolygon(Vector2 pos, Vector2[] points, Color color, int thickness = 1) { - _spriteBatch.DrawPolygon(pos, points, color, thickness); + SpriteBatch.DrawPolygon(pos, points, color, thickness); } public void DrawEllipse(Vector2 pos, Vector2 radius, Color color, int thickness = 1) { var sides = (int)Math.Max(radius.X, radius.Y) * 4; - _spriteBatch.DrawEllipse(pos, radius, sides, color, thickness); + SpriteBatch.DrawEllipse(pos, radius, sides, color, thickness); } public void Clear(Color? color = default) @@ -194,10 +194,10 @@ public class Drawing : IDisposable Vector2 position3 = new(rectangle.X, rectangle.Bottom - thickness); Vector2 scale = new(rectangle.Width, thickness); Vector2 scale2 = new(thickness, rectangle.Height); - _spriteBatch.Draw(_whitePixel, position, null, color, rotation, Vector2.Zero, scale, SpriteEffects.None, layerDepth); - _spriteBatch.Draw(_whitePixel, position, null, color, rotation, Vector2.Zero, scale2, SpriteEffects.None, layerDepth); - _spriteBatch.Draw(_whitePixel, position2, null, color, rotation, Vector2.Zero, scale2, SpriteEffects.None, layerDepth); - _spriteBatch.Draw(_whitePixel, position3, null, color, rotation, Vector2.Zero, scale, SpriteEffects.None, layerDepth); + SpriteBatch.Draw(_whitePixel, position, null, color, rotation, Vector2.Zero, scale, SpriteEffects.None, layerDepth); + SpriteBatch.Draw(_whitePixel, position, null, color, rotation, Vector2.Zero, scale2, SpriteEffects.None, layerDepth); + SpriteBatch.Draw(_whitePixel, position2, null, color, rotation, Vector2.Zero, scale2, SpriteEffects.None, layerDepth); + SpriteBatch.Draw(_whitePixel, position3, null, color, rotation, Vector2.Zero, scale, SpriteEffects.None, layerDepth); } public void DrawBuffer(uint[] buffer, Rectangle rect, Rectangle? source = null, Color? color = null, float rotation = 0f, Vector2? origin = null, float scale = 1f, SpriteEffects spriteEffects = 0) @@ -205,7 +205,7 @@ public class Drawing : IDisposable var texture = new Texture2D(_graphicsDevice, rect.Width, rect.Height, false, SurfaceFormat.Color); texture.SetData(buffer); - _spriteBatch.Draw( + SpriteBatch.Draw( texture, // Texture rect.Location.ToVector2(), // Position source, // source @@ -222,7 +222,7 @@ public class Drawing : IDisposable public void Dispose() { GC.SuppressFinalize(this); - _spriteBatch.Dispose(); + SpriteBatch.Dispose(); _whitePixel.Dispose(); } } diff --git a/Capy64/Runtime/EventEmitter.cs b/Capy64/Runtime/EventEmitter.cs index 83ca4ca..0ea20a7 100644 --- a/Capy64/Runtime/EventEmitter.cs +++ b/Capy64/Runtime/EventEmitter.cs @@ -185,9 +185,10 @@ internal class EventEmitter private void OnChar(object sender, CharEvent e) { + var i = (byte)Charset.GetIndex(e.Character); _runtime.QueueEvent("char", LK => { - LK.PushString(e.Character.ToString()); + LK.PushBuffer(new byte[] { i }); return 1; }); diff --git a/Capy64/Runtime/Libraries/Term.cs b/Capy64/Runtime/Libraries/Term.cs index 4ee77f7..1ddcdd5 100644 --- a/Capy64/Runtime/Libraries/Term.cs +++ b/Capy64/Runtime/Libraries/Term.cs @@ -14,6 +14,7 @@ // limitations under the License. using Capy64.API; +using Capy64.Core; using Capy64.Eventing.Events; using KeraLua; using Microsoft.Xna.Framework; @@ -25,7 +26,7 @@ namespace Capy64.Runtime.Libraries; internal class Term : IComponent { - private struct Char + private struct TermChar { public char Character; public Color Foreground; @@ -47,7 +48,7 @@ internal class Term : IComponent private static Vector2 _cursorPosition { get; set; } public static Color ForegroundColor { get; set; } public static Color BackgroundColor { get; set; } - private static Char?[] CharGrid; + private static TermChar?[] CharGrid; private static IGame _game; private static bool cursorState = false; @@ -204,7 +205,7 @@ internal class Term : IComponent _game.Drawing.DrawRectangle(realpos, new(CharWidth, CharHeight), bg, Math.Min(CharWidth, CharHeight)); //_game.Drawing.DrawRectangle(realpos, new(CharWidth, CharHeight), Color.Red, 1); - try + /*try { _game.Drawing.DrawString(charpos, ch.ToString(), fg); @@ -212,7 +213,10 @@ internal class Term : IComponent catch (ArgumentException ex) // UTF-16 fuckery { _game.Drawing.DrawString(charpos, "\xFFFD", fg); - } + }*/ + + var rect = Charset.Coords[(int)ch]; + _game.Drawing.SpriteBatch.Draw(Charset.Source, charpos, rect, fg); if(underline) { @@ -222,7 +226,7 @@ internal class Term : IComponent if (!save) return; - CharGrid[(int)pos.X + ((int)pos.Y * Width)] = new Char + CharGrid[(int)pos.X + ((int)pos.Y * Width)] = new TermChar { Character = ch, Foreground = ForegroundColor, @@ -237,7 +241,7 @@ internal class Term : IComponent return; var ch = CharGrid[(int)pos.X + ((int)pos.Y * Width)] ?? - new Char + new TermChar { Character = ' ', Foreground = ForegroundColor, @@ -312,7 +316,7 @@ internal class Term : IComponent private static void ClearGrid() { - CharGrid = new Char?[CharGrid.Length]; + CharGrid = new TermChar?[CharGrid.Length]; _game.Drawing.Clear(BackgroundColor); } @@ -320,7 +324,16 @@ internal class Term : IComponent { foreach (var ch in text) { - PlotChar(_cursorPosition, ch); + PlotChar(_cursorPosition, (char)ch); + _cursorPosition = new(_cursorPosition.X + 1, _cursorPosition.Y); + } + } + + public static void Write(byte[] buffer) + { + foreach (var b in buffer) + { + PlotChar(_cursorPosition, (char)b); _cursorPosition = new(_cursorPosition.X + 1, _cursorPosition.Y); } } @@ -328,9 +341,9 @@ internal class Term : IComponent private static int L_Write(IntPtr state) { var L = Lua.FromIntPtr(state); - string str = ""; + byte[] str = new byte[0]; if (!L.IsNone(1)) - str = L.ToString(1); + str = L.ToBuffer(1); Write(str); @@ -553,7 +566,7 @@ internal class Term : IComponent } var lineLength = Math.Abs(lines) * Width; - var newGrid = new Char?[CharGrid.Length]; + var newGrid = new TermChar?[CharGrid.Length]; if (lines < 0) { Array.Copy(CharGrid, lineLength, newGrid, 0, CharGrid.Length - lineLength); @@ -614,7 +627,7 @@ internal class Term : IComponent { var L = Lua.FromIntPtr(state); - var text = L.CheckString(1); + var text = L.CheckBuffer(1); L.CheckType(2, LuaType.Table); L.CheckType(3, LuaType.Table);