From e941a481eacf3d3675ca49e3fc76ec7420ae8766 Mon Sep 17 00:00:00 2001 From: Alessandro Proto Date: Sun, 5 Mar 2023 22:12:50 +0100 Subject: [PATCH] Classic mode --- Capy64/Assets/bios.lua | 10 - Capy64/Assets/default.json | 4 + Capy64/Capy64.cs | 63 +++++- Capy64/Core/ColorPalette.cs | 321 ++++++++++++++++++++++++++++ Capy64/Eventing/Events/TickEvent.cs | 1 + Capy64/IGame.cs | 1 + Capy64/Runtime/Libraries/GPU.cs | 68 +++--- Capy64/Runtime/Libraries/Term.cs | 24 ++- Capy64/Runtime/RuntimeManager.cs | 29 +-- 9 files changed, 433 insertions(+), 88 deletions(-) create mode 100644 Capy64/Core/ColorPalette.cs diff --git a/Capy64/Assets/bios.lua b/Capy64/Assets/bios.lua index db51d01..18f1349 100644 --- a/Capy64/Assets/bios.lua +++ b/Capy64/Assets/bios.lua @@ -35,7 +35,6 @@ term.setBackground(bg) term.clear() term.setSize(53, 20) -gpu.setScale(2) local w, h = term.getSize() @@ -157,11 +156,6 @@ local function installOS() promptKey() end -local function toggleConsole() - local status = getConsole() - setConsole(not status) -end - term.setBlink(false) local function setupScreen() @@ -170,10 +164,6 @@ local function setupScreen() "Open data folder", openDataFolder, }, - { - "Toggle console window", - toggleConsole, - }, { "Install default OS", installOS, diff --git a/Capy64/Assets/default.json b/Capy64/Assets/default.json index 85dca20..6b04894 100644 --- a/Capy64/Assets/default.json +++ b/Capy64/Assets/default.json @@ -1,4 +1,8 @@ { + "EngineMode": 0, + "Window": { + "Scale": 2 + }, "HTTP": { "Enable": true, "Blacklist": [], diff --git a/Capy64/Capy64.cs b/Capy64/Capy64.cs index c824ae8..4b890ac 100644 --- a/Capy64/Capy64.cs +++ b/Capy64/Capy64.cs @@ -20,6 +20,7 @@ using Capy64.Extensions; using Capy64.Integrations; using Capy64.PluginManager; using Capy64.Runtime; +using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Xna.Framework; using Microsoft.Xna.Framework.Graphics; @@ -33,9 +34,29 @@ using static Capy64.Utils; namespace Capy64; +public enum EngineMode +{ + Classic, + Free +} + + public class Capy64 : Game, IGame { - public const string Version = "0.0.9-alpha"; + public const string Version = "0.0.10-alpha"; + + public static class DefaultParameters + { + public const int Width = 318; + public const int Height = 240; + public const float Scale = 2f; + public const float BorderMultiplier = 1.5f; + public readonly static EngineMode EngineMode = EngineMode.Classic; + + public const int ClassicTickrate = 20; + public const int FreeTickrate = 60; + } + public static string AppDataPath { @@ -56,11 +77,12 @@ public class Capy64 : Game, IGame public static Capy64 Instance { get; private set; } public Capy64 Game => this; + public EngineMode EngineMode { get; private set; } = EngineMode.Classic; public IList NativePlugins { get; private set; } public IList Plugins { get; private set; } - public int Width { get; set; } = 320; - public int Height { get; set; } = 240; - public float Scale { get; set; } = 2f; + public int Width { get; set; } = DefaultParameters.Width; + public int Height { get; set; } = DefaultParameters.Height; + public float Scale { get; set; } = DefaultParameters.Scale; public Drawing Drawing { get; private set; } public Audio Audio { get; private set; } public LuaState LuaRuntime { get; set; } @@ -83,6 +105,7 @@ public class Capy64 : Game, IGame private readonly GraphicsDeviceManager _graphics; private IServiceProvider _serviceProvider; private ulong _totalTicks = 0; + private ulong tickrate = 0; public Capy64() { @@ -103,6 +126,27 @@ public class Capy64 : Game, IGame _serviceProvider = serviceProvider; } + public void SetEngineMode(EngineMode mode) + { + switch (mode) + { + case EngineMode.Classic: + tickrate = DefaultParameters.ClassicTickrate; + Width = DefaultParameters.Width; + Height = DefaultParameters.Height; + Window.AllowUserResizing = false; + ResetBorder(); + + break; + + case EngineMode.Free: + tickrate = DefaultParameters.FreeTickrate; + Window.AllowUserResizing = true; + break; + } + UpdateSize(true); + } + public void UpdateSize(bool resize = true) { if (resize) @@ -157,7 +201,7 @@ public class Capy64 : Game, IGame private void ResetBorder() { - var size = (int)(Scale * 1.5); + var size = (int)(Scale * DefaultParameters.BorderMultiplier); Borders = new Borders { Top = size, @@ -169,8 +213,12 @@ public class Capy64 : Game, IGame protected override void Initialize() { + var configuration = _serviceProvider.GetService(); + Window.Title = "Capy64 " + Version; + Scale = configuration.GetValue("Window:Scale", DefaultParameters.Scale); + ResetBorder(); UpdateSize(); @@ -179,6 +227,8 @@ public class Capy64 : Game, IGame InactiveSleepTime = new TimeSpan(0); + SetEngineMode(configuration.GetValue("EngineMode", DefaultParameters.EngineMode)); + Audio = new Audio(); NativePlugins = GetNativePlugins(); @@ -222,7 +272,8 @@ public class Capy64 : Game, IGame EventEmitter.RaiseTick(new() { GameTime = gameTime, - TotalTicks = _totalTicks + TotalTicks = _totalTicks, + IsActiveTick = _totalTicks % (60 / tickrate) == 0, }); Drawing.End(); diff --git a/Capy64/Core/ColorPalette.cs b/Capy64/Core/ColorPalette.cs new file mode 100644 index 0000000..9f6ba09 --- /dev/null +++ b/Capy64/Core/ColorPalette.cs @@ -0,0 +1,321 @@ +// 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 Microsoft.Xna.Framework; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Capy64.Core; + +public class ColorPalette +{ + public static int GetIndex(int r, int g, int b) + { + r /= 51; + g /= 51; + b /= 51; + return 16 + (36 * r) + (6 * g) + b; + } + + public static int GetIndex(Color color) + { + return GetIndex(color.R, color.G, color.B); + } + + public static int GetIndex(uint packed) + { + var b = (byte)(packed & 0xff); + var g = (byte)((packed >> 8) & 0xff); + var r = (byte)((packed >> 16) & 0xff); + return GetIndex(r, g, b); + } + + public static uint GetColor(int r, int g, int b) + { + return Palette[GetIndex(r, g, b)]; + } + + public static uint GetColor(Color color) + { + return Palette[GetIndex(color)]; + } + + public static uint GetColor(uint packed) + { + return Palette[GetIndex(packed)]; + } + + public static readonly uint[] Palette = new uint[] { + 0x000000, + 0x800000, + 0x008000, + 0x808000, + 0x000080, + 0x800080, + 0x008080, + 0xC0C0C0, + 0x808080, + 0xFF0000, + 0x00FF00, + 0xFFFF00, + 0x0000FF, + 0xFF00FF, + 0x00FFFF, + 0xFFFFFF, + 0x000000, + 0x00005F, + 0x000087, + 0x0000AF, + 0x0000D7, + 0x0000FF, + 0x005F00, + 0x005F5F, + 0x005F87, + 0x005FAF, + 0x005FD7, + 0x005FFF, + 0x008700, + 0x00875F, + 0x008787, + 0x0087AF, + 0x0087D7, + 0x0087FF, + 0x00AF00, + 0x00AF5F, + 0x00AF87, + 0x00AFAF, + 0x00AFD7, + 0x00AFFF, + 0x00D700, + 0x00D75F, + 0x00D787, + 0x00D7AF, + 0x00D7D7, + 0x00D7FF, + 0x00FF00, + 0x00FF5F, + 0x00FF87, + 0x00FFAF, + 0x00FFD7, + 0x00FFFF, + 0x5F0000, + 0x5F005F, + 0x5F0087, + 0x5F00AF, + 0x5F00D7, + 0x5F00FF, + 0x5F5F00, + 0x5F5F5F, + 0x5F5F87, + 0x5F5FAF, + 0x5F5FD7, + 0x5F5FFF, + 0x5F8700, + 0x5F875F, + 0x5F8787, + 0x5F87AF, + 0x5F87D7, + 0x5F87FF, + 0x5FAF00, + 0x5FAF5F, + 0x5FAF87, + 0x5FAFAF, + 0x5FAFD7, + 0x5FAFFF, + 0x5FD700, + 0x5FD75F, + 0x5FD787, + 0x5FD7AF, + 0x5FD7D7, + 0x5FD7FF, + 0x5FFF00, + 0x5FFF5F, + 0x5FFF87, + 0x5FFFAF, + 0x5FFFD7, + 0x5FFFFF, + 0x870000, + 0x87005F, + 0x870087, + 0x8700AF, + 0x8700D7, + 0x8700FF, + 0x875F00, + 0x875F5F, + 0x875F87, + 0x875FAF, + 0x875FD7, + 0x875FFF, + 0x878700, + 0x87875F, + 0x878787, + 0x8787AF, + 0x8787D7, + 0x8787FF, + 0x87AF00, + 0x87AF5F, + 0x87AF87, + 0x87AFAF, + 0x87AFD7, + 0x87AFFF, + 0x87D700, + 0x87D75F, + 0x87D787, + 0x87D7AF, + 0x87D7D7, + 0x87D7FF, + 0x87FF00, + 0x87FF5F, + 0x87FF87, + 0x87FFAF, + 0x87FFD7, + 0x87FFFF, + 0xAF0000, + 0xAF005F, + 0xAF0087, + 0xAF00AF, + 0xAF00D7, + 0xAF00FF, + 0xAF5F00, + 0xAF5F5F, + 0xAF5F87, + 0xAF5FAF, + 0xAF5FD7, + 0xAF5FFF, + 0xAF8700, + 0xAF875F, + 0xAF8787, + 0xAF87AF, + 0xAF87D7, + 0xAF87FF, + 0xAFAF00, + 0xAFAF5F, + 0xAFAF87, + 0xAFAFAF, + 0xAFAFD7, + 0xAFAFFF, + 0xAFD700, + 0xAFD75F, + 0xAFD787, + 0xAFD7AF, + 0xAFD7D7, + 0xAFD7FF, + 0xAFFF00, + 0xAFFF5F, + 0xAFFF87, + 0xAFFFAF, + 0xAFFFD7, + 0xAFFFFF, + 0xD70000, + 0xD7005F, + 0xD70087, + 0xD700AF, + 0xD700D7, + 0xD700FF, + 0xD75F00, + 0xD75F5F, + 0xD75F87, + 0xD75FAF, + 0xD75FD7, + 0xD75FFF, + 0xD78700, + 0xD7875F, + 0xD78787, + 0xD787AF, + 0xD787D7, + 0xD787FF, + 0xD7AF00, + 0xD7AF5F, + 0xD7AF87, + 0xD7AFAF, + 0xD7AFD7, + 0xD7AFFF, + 0xD7D700, + 0xD7D75F, + 0xD7D787, + 0xD7D7AF, + 0xD7D7D7, + 0xD7D7FF, + 0xD7FF00, + 0xD7FF5F, + 0xD7FF87, + 0xD7FFAF, + 0xD7FFD7, + 0xD7FFFF, + 0xFF0000, + 0xFF005F, + 0xFF0087, + 0xFF00AF, + 0xFF00D7, + 0xFF00FF, + 0xFF5F00, + 0xFF5F5F, + 0xFF5F87, + 0xFF5FAF, + 0xFF5FD7, + 0xFF5FFF, + 0xFF8700, + 0xFF875F, + 0xFF8787, + 0xFF87AF, + 0xFF87D7, + 0xFF87FF, + 0xFFAF00, + 0xFFAF5F, + 0xFFAF87, + 0xFFAFAF, + 0xFFAFD7, + 0xFFAFFF, + 0xFFD700, + 0xFFD75F, + 0xFFD787, + 0xFFD7AF, + 0xFFD7D7, + 0xFFD7FF, + 0xFFFF00, + 0xFFFF5F, + 0xFFFF87, + 0xFFFFAF, + 0xFFFFD7, + 0xFFFFFF, + 0x080808, + 0x121212, + 0x1C1C1C, + 0x262626, + 0x303030, + 0x3A3A3A, + 0x444444, + 0x4E4E4E, + 0x585858, + 0x626262, + 0x6C6C6C, + 0x767676, + 0x808080, + 0x8A8A8A, + 0x949494, + 0x9E9E9E, + 0xA8A8A8, + 0xB2B2B2, + 0xBCBCBC, + 0xC6C6C6, + 0xD0D0D0, + 0xDADADA, + 0xE4E4E4, + 0xEEEEEE, + }; +} diff --git a/Capy64/Eventing/Events/TickEvent.cs b/Capy64/Eventing/Events/TickEvent.cs index a554f76..b51d881 100644 --- a/Capy64/Eventing/Events/TickEvent.cs +++ b/Capy64/Eventing/Events/TickEvent.cs @@ -22,4 +22,5 @@ public class TickEvent : EventArgs { public GameTime GameTime { get; set; } public ulong TotalTicks { get; set; } + public bool IsActiveTick { get; set; } } diff --git a/Capy64/IGame.cs b/Capy64/IGame.cs index 9a63019..c7c878b 100644 --- a/Capy64/IGame.cs +++ b/Capy64/IGame.cs @@ -26,6 +26,7 @@ namespace Capy64; public interface IGame { Capy64 Game { get; } + EngineMode EngineMode { get; } IList NativePlugins { get; } IList Plugins { get; } GameWindow Window { get; } diff --git a/Capy64/Runtime/Libraries/GPU.cs b/Capy64/Runtime/Libraries/GPU.cs index 2130342..4c8fee1 100644 --- a/Capy64/Runtime/Libraries/GPU.cs +++ b/Capy64/Runtime/Libraries/GPU.cs @@ -14,6 +14,7 @@ // limitations under the License. using Capy64.API; +using Capy64.Core; using Capy64.Runtime.Objects; using KeraLua; using Microsoft.Xna.Framework; @@ -45,16 +46,6 @@ public class GPU : IComponent function = L_SetSize, }, new() - { - name = "getScale", - function = L_GetScale, - }, - new() - { - name = "setScale", - function = L_SetScale, - }, - new() { name = "getPixel", function = L_GetPixel, @@ -153,6 +144,14 @@ public class GPU : IComponent l.NewLib(gpuLib); return 1; } + + public static void GetColor(uint c, out byte r, out byte g, out byte b) + { + if (_game.EngineMode == EngineMode.Classic) + c = ColorPalette.GetColor(c); + Utils.UnpackRGB(c, out r, out g, out b); + } + private static int L_GetSize(IntPtr state) { var L = Lua.FromIntPtr(state); @@ -167,6 +166,12 @@ public class GPU : IComponent { var L = Lua.FromIntPtr(state); + if (_game.EngineMode == EngineMode.Classic) + { + L.PushBoolean(false); + return 1; + } + var w = L.CheckInteger(1); var h = L.CheckInteger(2); @@ -175,31 +180,11 @@ public class GPU : IComponent _game.UpdateSize(); - return 0; - } - - private static int L_GetScale(IntPtr state) - { - var L = Lua.FromIntPtr(state); - - L.PushNumber(_game.Scale); + L.PushBoolean(true); return 1; } - private static int L_SetScale(IntPtr state) - { - var L = Lua.FromIntPtr(state); - - var s = L.CheckNumber(1); - - _game.Scale = (float)s; - - _game.UpdateSize(); - - return 0; - } - private static int L_GetPixel(IntPtr state) { var L = Lua.FromIntPtr(state); @@ -222,7 +207,7 @@ public class GPU : IComponent var y = (int)L.CheckNumber(2) - 1; var c = L.CheckInteger(3); - Utils.UnpackRGB((uint)c, out var r, out var g, out var b); + GetColor((uint)c, out var r, out var g, out var b); _game.Drawing.Plot(new Point(x, y), new Color(r, g, b)); return 0; @@ -257,7 +242,7 @@ public class GPU : IComponent pts.Add(new Point(x, y)); } - Utils.UnpackRGB((uint)c, out var r, out var g, out var b); + GetColor((uint)c, out var r, out var g, out var b); _game.Drawing.Plot(pts, new(r, g, b)); return 0; @@ -272,7 +257,7 @@ public class GPU : IComponent var c = L.CheckInteger(3); var s = (int)L.OptNumber(4, 1); - Utils.UnpackRGB((uint)c, out var r, out var g, out var b); + GetColor((uint)c, out var r, out var g, out var b); _game.Drawing.DrawPoint(new(x, y), new Color(r, g, b), s); return 0; @@ -289,7 +274,7 @@ public class GPU : IComponent var t = (int)L.OptNumber(5, 1); var s = (int)L.OptInteger(6, -1); - Utils.UnpackRGB((uint)c, out var r, out var g, out var b); + GetColor((uint)c, out var r, out var g, out var b); _game.Drawing.DrawCircle(new(x, y), rad, new Color(r, g, b), t, s); return 0; @@ -306,7 +291,7 @@ public class GPU : IComponent var c = L.CheckInteger(5); var s = (int)L.OptNumber(6, 1); - Utils.UnpackRGB((uint)c, out var r, out var g, out var b); + GetColor((uint)c, out var r, out var g, out var b); _game.Drawing.DrawLine(new(x1, y1), new(x2, y2), new Color(r, g, b), s); return 0; @@ -323,7 +308,7 @@ public class GPU : IComponent var c = L.CheckInteger(5); var s = (int)L.OptNumber(6, 1); - Utils.UnpackRGB((uint)c, out var r, out var g, out var b); + GetColor((uint)c, out var r, out var g, out var b); _game.Drawing.DrawRectangle(new(x, y), new(w, h), new Color(r, g, b), s); return 0; @@ -359,7 +344,7 @@ public class GPU : IComponent pts.Add(new(xp, yp)); } - Utils.UnpackRGB((uint)c, out var r, out var g, out var b); + GetColor((uint)c, out var r, out var g, out var b); _game.Drawing.DrawPolygon(new(x, y), pts.ToArray(), new(r, g, b), s); return 0; @@ -376,7 +361,7 @@ public class GPU : IComponent var c = L.CheckInteger(5); var s = (int)L.OptNumber(6, 1); - Utils.UnpackRGB((uint)c, out var r, out var g, out var b); + GetColor((uint)c, out var r, out var g, out var b); _game.Drawing.DrawEllipse(new(x, y), new(rx, ry), new Color(r, g, b), s); return 0; @@ -391,7 +376,7 @@ public class GPU : IComponent var c = L.CheckInteger(3); var t = L.CheckString(4); - Utils.UnpackRGB((uint)c, out var r, out var g, out var b); + GetColor((uint)c, out var r, out var g, out var b); try { _game.Drawing.DrawString(new Vector2(x, y), t, new Color(r, g, b)); @@ -426,7 +411,6 @@ public class GPU : IComponent _game.Drawing.Canvas.GetData(buffer); ObjectManager.PushObject(L, buffer); - //L.PushObject(buffer); L.SetMetaTable(GPUBuffer.ObjectType); return 1; @@ -529,7 +513,7 @@ public class GPU : IComponent var c = L.OptInteger(1, 0x000000); - Utils.UnpackRGB((uint)c, out var r, out var g, out var b); + GetColor((uint)c, out var r, out var g, out var b); _game.Drawing.Clear(new Color(r, g, b)); return 0; diff --git a/Capy64/Runtime/Libraries/Term.cs b/Capy64/Runtime/Libraries/Term.cs index 1d42d78..fa2824e 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; @@ -174,6 +175,13 @@ internal class Term : IComponent return 1; } + public static void GetColor(uint c, out byte r, out byte g, out byte b) + { + if (_game.EngineMode == EngineMode.Classic) + c = ColorPalette.GetColor(c); + UnpackRGB(c, out r, out g, out b); + } + public static void UpdateSize(bool resize = true) { Array.Resize(ref CharGrid, Width * Height); @@ -388,6 +396,12 @@ internal class Term : IComponent { var L = Lua.FromIntPtr(state); + if(_game.EngineMode == EngineMode.Classic) + { + L.PushBoolean(false); + return 1; + } + var w = (int)L.CheckNumber(1); var h = (int)L.CheckNumber(2); @@ -402,7 +416,8 @@ internal class Term : IComponent SetSize(w, h); - return 0; + L.PushBoolean(true); + return 1; } private static int L_GetForegroundColor(IntPtr state) @@ -427,12 +442,14 @@ internal class Term : IComponent r = (byte)L.CheckNumber(1); g = (byte)L.CheckNumber(2); b = (byte)L.CheckNumber(3); + UnpackRGB(ColorPalette.GetColor(r, g, b), out r, out g, out b); + } // packed RGB value else if (argsn == 1) { var c = (uint)L.CheckInteger(1); - UnpackRGB(c, out r, out g, out b); + GetColor(c, out r, out g, out b); } else { @@ -467,12 +484,13 @@ internal class Term : IComponent r = (byte)L.CheckNumber(1); g = (byte)L.CheckNumber(2); b = (byte)L.CheckNumber(3); + UnpackRGB(ColorPalette.GetColor(r, g, b), out r, out g, out b); } // packed RGB value else if (argsn == 1) { var c = (uint)L.CheckInteger(1); - UnpackRGB(c, out r, out g, out b); + GetColor(c, out r, out g, out b); } else { diff --git a/Capy64/Runtime/RuntimeManager.cs b/Capy64/Runtime/RuntimeManager.cs index 54cfca9..cf150d7 100644 --- a/Capy64/Runtime/RuntimeManager.cs +++ b/Capy64/Runtime/RuntimeManager.cs @@ -123,12 +123,6 @@ internal class RuntimeManager : IComponent luaState.Thread.PushCFunction(L_Exit); luaState.Thread.SetGlobal("exit"); - luaState.Thread.PushCFunction(L_SetConsole); - luaState.Thread.SetGlobal("setConsole"); - - luaState.Thread.PushCFunction(L_GetConsole); - luaState.Thread.SetGlobal("getConsole"); - var status = luaState.Thread.LoadFile("Assets/bios.lua"); if (status != LuaStatus.OK) { @@ -219,26 +213,6 @@ internal class RuntimeManager : IComponent return 0; } - private static int L_SetConsole(IntPtr state) - { - var L = Lua.FromIntPtr(state); - - var status = L.ToBoolean(1); - _game.Window.ToggleConsole(status); - - return 0; - } - - private static int L_GetConsole(IntPtr state) - { - var L = Lua.FromIntPtr(state); - - var status = _game.Window.IsConsoleVisible(); - L.PushBoolean(status); - - return 1; - } - private void OnInit(object sender, EventArgs e) { Start(); @@ -246,6 +220,7 @@ internal class RuntimeManager : IComponent private void OnTick(object sender, TickEvent e) { - Resume(); + if (e.IsActiveTick) + Resume(); } }