Adapting InputManager to SDL

This commit is contained in:
Ale32bit 2023-09-02 10:12:24 +02:00
parent 0d358b09b9
commit 110afd1ca4
26 changed files with 579 additions and 495 deletions

View file

@ -1,49 +1,68 @@
// This file is part of Capy64 - https://github.com/Ale32bit/Capy64 // This file is part of Capy64 - https://github.com/Ale32bit/Capy64
// Copyright 2023 Alessandro "AlexDevs" Proto // Copyright 2023 Alessandro "AlexDevs" Proto
// //
// Licensed under the Apache License, Version 2.0 (the "License"). // Licensed under the Apache License, Version 2.0 (the "License").
// you may not use this file except in compliance with the License. // you may not use this file except in compliance with the License.
// You may obtain a copy of the License at // You may obtain a copy of the License at
// //
// http://www.apache.org/licenses/LICENSE-2.0 // http://www.apache.org/licenses/LICENSE-2.0
// //
// Unless required by applicable law or agreed to in writing, software // Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS, // distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and // See the License for the specific language governing permissions and
// limitations under the License. // limitations under the License.
using Capy64.API;
using Capy64.Core;
using Capy64.Eventing; using Capy64.Eventing;
using Capy64.Extensions;
using Capy64.Integrations;
using Capy64.PluginManager;
using Capy64.Runtime;
using Microsoft.Extensions.Configuration;
using Microsoft.Xna.Framework; using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using MonoGame.Extended;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.InteropServices;
using static Capy64.Utils;
namespace Capy64; namespace Capy64;
public enum EngineMode using System;
{ using System.IO;
Classic, using System.Reflection;
Free using System.Runtime.InteropServices;
} using static Utils;
using static SDL2.SDL;
public class Capy64 : Game public class Capy64 : IDisposable
{ {
public const string Version = "1.1.0-beta"; public const string Version = "1.1.0-beta";
public nint Window { get; private set; } = 0;
public nint Renderer { get; private set; } = 0;
public nint VideoSurface { get; private set; } = 0;
public nint SurfaceRenderer { get; private set; } = 0;
public int WindowWidth { get; private set; }
public int WindowHeight { get; private set; }
public int Width { get; set; } = DefaultParameters.Width;
public int Height { get; set; } = DefaultParameters.Height;
public float Scale { get; set; } = DefaultParameters.Scale;
public int Tickrate { get; set; } = DefaultParameters.ClassicTickrate;
public int Framerate { get; set; } = 60;
public float Ticktime => 1000f / Tickrate;
public float Frametime => 1000f / Framerate;
public Color BorderColor { get; set; } = Color.Blue;
public Borders Borders {
get => _borders;
set {
_borders = value;
_outputRect = new() {
x = value.Left,
y = value.Top,
w = (int)(Width * Scale),
h = (int)(Height * Scale),
};
}
}
private SDL_Rect _outputRect;
private Borders _borders;
public static readonly string AssemblyPath = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
public static readonly string AssetsPath = Path.Combine(AssemblyPath, "Assets");
public static class DefaultParameters public static class DefaultParameters
{ {
@ -57,165 +76,41 @@ public class Capy64 : Game
public const int FreeTickrate = 60; public const int FreeTickrate = 60;
} }
public static readonly string AssemblyPath = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location); public static string AppDataPath {
public static readonly string AssetsPath = Path.Combine(AssemblyPath, "Assets"); get {
public static string AppDataPath
{
get
{
string baseDir = string baseDir =
RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? Environment.GetFolderPath(
Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData, Environment.SpecialFolder.ApplicationData,
Environment.SpecialFolderOption.Create) : Environment.SpecialFolderOption.Create) :
RuntimeInformation.IsOSPlatform(OSPlatform.Linux) ? RuntimeInformation.IsOSPlatform(OSPlatform.Linux) ? Environment.GetFolderPath(
Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData, Environment.SpecialFolder.LocalApplicationData,
Environment.SpecialFolderOption.Create) : Environment.SpecialFolderOption.Create) :
RuntimeInformation.IsOSPlatform(OSPlatform.OSX) ? RuntimeInformation.IsOSPlatform(OSPlatform.OSX) ? Environment.GetFolderPath(
Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData, Environment.SpecialFolder.LocalApplicationData,
Environment.SpecialFolderOption.Create) : Environment.SpecialFolderOption.Create) :
"./"; "./";
return Path.Combine(baseDir, "Capy64"); return Path.Combine(baseDir, "Capy64");
} }
} }
public static Capy64 Instance { get; private set; } private bool _running = false;
public Capy64 Game => this; private InputManager _inputManager;
public EngineMode EngineMode { get; private set; } = EngineMode.Classic; public EventEmitter EventEmitter = new();
public IList<IComponent> NativePlugins { get; private set; }
public IList<IComponent> Plugins { get; private set; }
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; }
public Eventing.EventEmitter EventEmitter { get; private set; }
public DiscordIntegration Discord { get; set; }
public int TickRate => tickrate;
public IConfiguration Configuration { get; private set; }
public Color BorderColor { get; set; } = Color.Black;
public Borders Borders = new()
{
Top = 0,
Bottom = 0,
Left = 0,
Right = 0,
};
public SpriteBatch SpriteBatch;
private readonly InputManager _inputManager;
private RenderTarget2D renderTarget;
private readonly GraphicsDeviceManager _graphics;
private ulong _totalTicks = 0;
private int tickrate = 0;
private int everyTick => 60 / tickrate;
public Capy64() public Capy64()
{ {
Instance = this; ResetBorder();
WindowWidth = (int)(Width * Scale) + Borders.Left + Borders.Right;
WindowHeight = (int)(Height * Scale) + Borders.Top + Borders.Bottom;
_graphics = new GraphicsDeviceManager(this); _inputManager = new(null, EventEmitter);
//Content.RootDirectory = "Content";
IsMouseVisible = true;
EventEmitter = new();
_inputManager = new(this, EventEmitter);
Drawing = new();
}
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;
}
EngineMode = mode;
UpdateSize(true);
}
public void UpdateSize(bool resize = true)
{
if (resize)
{
_graphics.PreferredBackBufferWidth = (int)(Width * Scale) + Borders.Left + Borders.Right;
_graphics.PreferredBackBufferHeight = (int)(Height * Scale) + Borders.Top + Borders.Bottom;
_graphics.ApplyChanges();
}
renderTarget = new RenderTarget2D(
GraphicsDevice,
Width,
Height,
false,
GraphicsDevice.PresentationParameters.BackBufferFormat,
DepthFormat.Depth24, 0, RenderTargetUsage.PreserveContents);
Drawing.Canvas = renderTarget;
_inputManager.Texture = renderTarget;
EventEmitter.RaiseScreenSizeChange();
}
private void OnWindowSizeChange(object sender, EventArgs e)
{
if (EngineMode == EngineMode.Classic)
{
UpdateSize(true);
return;
}
var bounds = Window.ClientBounds;
Width = (int)(bounds.Width / Scale);
Height = (int)(bounds.Height / Scale);
if (Window.IsMaximized())
{
var vertical = bounds.Height - (Height * Scale);
var horizontal = bounds.Width - (Width * Scale);
Borders.Top = (int)Math.Floor(vertical / 2d);
Borders.Bottom = (int)Math.Ceiling(vertical / 2d);
Borders.Left = (int)Math.Floor(horizontal / 2d);
Borders.Right = (int)Math.Ceiling(horizontal / 2d);
UpdateSize(false);
}
else
{
ResetBorder();
UpdateSize();
}
} }
private void ResetBorder() private void ResetBorder()
{ {
var size = (int)(Scale * DefaultParameters.BorderMultiplier); var size = (int)(Scale * DefaultParameters.BorderMultiplier);
Borders = new Borders Borders = new Borders {
{
Top = size, Top = size,
Bottom = size, Bottom = size,
Left = size, Left = size,
@ -223,116 +118,113 @@ public class Capy64 : Game
}; };
} }
protected override void Initialize() public void Run()
{ {
var configBuilder = new ConfigurationBuilder(); #if DEBUG
SDL_SetHint(SDL_HINT_WINDOWS_DISABLE_THREAD_NAMING, "1");
#endif
var settingsPath = Path.Combine(AppDataPath, "settings.json"); if (SDL_Init(SDL_INIT_EVERYTHING) != 0)
if (!Directory.Exists(AppDataPath))
{ {
Directory.CreateDirectory(AppDataPath); Console.WriteLine(SDL_GetError());
} return;
if (!File.Exists(settingsPath))
{
File.Copy(Path.Combine(AssetsPath, "default.json"), settingsPath);
} }
configBuilder.AddJsonFile(Path.Combine(AssetsPath, "default.json"), false); Window = SDL_CreateWindow("Capy64 " + Version,
configBuilder.AddJsonFile(settingsPath, false); SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED,
WindowWidth, WindowHeight,
SDL_WindowFlags.SDL_WINDOW_OPENGL);
Configuration = configBuilder.Build(); if (Window == nint.Zero)
Window.Title = "Capy64 " + Version;
Scale = Configuration.GetValue("Window:Scale", DefaultParameters.Scale);
ResetBorder();
UpdateSize();
Window.AllowUserResizing = true;
Window.ClientSizeChanged += OnWindowSizeChange;
InactiveSleepTime = new TimeSpan(0);
SetEngineMode(Configuration.GetValue<EngineMode>("EngineMode", DefaultParameters.EngineMode));
Audio = new Audio();
NativePlugins = GetNativePlugins();
var safeMode = Configuration.GetValue("SafeMode", false);
if (!safeMode)
Plugins = PluginLoader.LoadAllPlugins(Path.Combine(AppDataPath, "plugins"));
EventEmitter.RaiseInit();
base.Initialize();
}
private List<IComponent> GetNativePlugins()
{
var iType = typeof(IComponent);
var types = AppDomain.CurrentDomain.GetAssemblies()
.SelectMany(s => s.GetTypes())
.Where(p => iType.IsAssignableFrom(p) && !p.IsInterface);
var plugins = new List<IComponent>();
foreach (var type in types)
{ {
var instance = (IComponent)Activator.CreateInstance(type, this); Console.WriteLine(SDL_GetError());
plugins.Add(instance); return;
} }
return plugins; var icon = SDL_LoadBMP("./Icon.bmp");
} if(icon != 0)
SDL_SetWindowIcon(Window, icon);
Renderer = SDL_CreateRenderer(Window,
0,
SDL_RendererFlags.SDL_RENDERER_ACCELERATED | SDL_RendererFlags.SDL_RENDERER_PRESENTVSYNC);
protected override void LoadContent() if (Renderer == nint.Zero)
{
SpriteBatch = new SpriteBatch(GraphicsDevice);
}
protected override void Update(GameTime gameTime)
{
Drawing.Begin();
// Register user input
_inputManager.Update(IsActive);
EventEmitter.RaiseTick(new()
{ {
GameTime = gameTime, Console.WriteLine(SDL_GetError());
TotalTicks = _totalTicks, return;
IsActiveTick = (int)_totalTicks % everyTick == 0, }
});
Drawing.End(); VideoSurface = SDL_CreateRGBSurfaceWithFormat(0, Width, Height, 32, SDL_PIXELFORMAT_ARGB8888);
SurfaceRenderer = SDL_CreateSoftwareRenderer(VideoSurface);
_totalTicks++; SDL_SetRenderDrawColor(SurfaceRenderer, 255, 255, 255, 255);
SDL_RenderClear(SurfaceRenderer);
base.Update(gameTime); _running = true;
ulong deltaEnd = 0;
var perfFreq = SDL_GetPerformanceFrequency();
while (_running)
{
var deltaStart = SDL_GetPerformanceCounter();
var delta = deltaStart - deltaEnd;
while (SDL_PollEvent(out var ev) != 0)
{
ProcessEvent(ev);
}
if ((uint)(perfFreq / delta) >= Framerate)
{
continue;
}
deltaEnd = deltaStart;
SDL_SetRenderDrawColor(Renderer, BorderColor.R, BorderColor.G, BorderColor.B, 255);
SDL_RenderClear(Renderer);
SDL_SetRenderDrawColor(Renderer, 255, 255, 255, 255);
var texture = SDL_CreateTextureFromSurface(Renderer, VideoSurface);
SDL_SetRenderDrawBlendMode(Renderer, SDL_BlendMode.SDL_BLENDMODE_BLEND);
SDL_RenderCopy(Renderer, texture, 0, ref _outputRect);
SDL_DestroyTexture(texture);
SDL_RenderPresent(Renderer);
}
} }
protected override void Draw(GameTime gameTime) private void ProcessEvent(SDL_Event ev)
{ {
SpriteBatch.Begin(SpriteSortMode.Deferred, BlendState.AlphaBlend, SamplerState.PointClamp); switch (ev.type)
GraphicsDevice.Clear(BorderColor);
SpriteBatch.DrawRectangle(renderTarget.Bounds.Location.ToVector2() + new Vector2(Borders.Left, Borders.Top),
new Size2(renderTarget.Bounds.Width * Scale, renderTarget.Bounds.Height * Scale), Color.Black,
Math.Min(renderTarget.Bounds.Width, renderTarget.Bounds.Height), 0);
SpriteBatch.Draw(renderTarget, new(Borders.Left, Borders.Top), null, Color.White, 0f, Vector2.Zero, Scale,
SpriteEffects.None, 0);
EventEmitter.RaiseOverlay(new()
{ {
GameTime = gameTime, case SDL_EventType.SDL_QUIT:
TotalTicks = _totalTicks, _running = false;
}); break;
SpriteBatch.End(); case SDL_EventType.SDL_KEYDOWN:
break;
base.Draw(gameTime); case SDL_EventType.SDL_MOUSEBUTTONUP:
case SDL_EventType.SDL_MOUSEBUTTONDOWN:
unsafe
{
var pitch = ((SDL_Surface*)VideoSurface)->pitch;
((uint*)((SDL_Surface*)VideoSurface)->pixels)[x + y * pitch / 4] = 0xFFFF00FF;
}
break;
}
}
public void Dispose()
{
SDL_DestroyRenderer(SurfaceRenderer);
SDL_FreeSurface(VideoSurface);
SDL_DestroyRenderer(Renderer);
SDL_DestroyWindow(Window);
SDL_Quit();
} }
} }

View file

@ -53,7 +53,7 @@ public class Audio : IDisposable
private static void EnqueueAudioNeedEvent(int i, int pending) private static void EnqueueAudioNeedEvent(int i, int pending)
{ {
Capy64.Instance.LuaRuntime.QueueEvent("audio_need", LK => LegacyEntry.Instance.LuaRuntime.QueueEvent("audio_need", LK =>
{ {
LK.PushInteger(i); LK.PushInteger(i);
LK.PushInteger(pending); LK.PushInteger(pending);

View file

@ -54,7 +54,7 @@ public class Drawing : IDisposable
public Drawing() public Drawing()
{ {
_fontSystem = new FontSystem(); _fontSystem = new FontSystem();
_fontSystem.AddFont(File.ReadAllBytes(Path.Combine(Capy64.AssetsPath, "font.ttf"))); _fontSystem.AddFont(File.ReadAllBytes(Path.Combine(LegacyEntry.AssetsPath, "font.ttf")));
} }
public void Begin() public void Begin()
@ -184,7 +184,7 @@ public class Drawing : IDisposable
public void Clear(Color? color = default) public void Clear(Color? color = default)
{ {
Color finalColor = color ?? Color.Black; Color finalColor = color ?? Color.Black;
Capy64.Instance.BorderColor = finalColor; LegacyEntry.Instance.BorderColor = finalColor;
_graphicsDevice.Clear(finalColor); _graphicsDevice.Clear(finalColor);
} }

View file

@ -19,6 +19,7 @@ using Microsoft.Xna.Framework.Input;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using SDL2;
namespace Capy64.Eventing; namespace Capy64.Eventing;
@ -74,7 +75,7 @@ public class InputManager
}; };
public Texture2D Texture { get; set; } public Texture2D Texture { get; set; }
public static float WindowScale => Capy64.Instance.Scale; public static float WindowScale => LegacyEntry.Instance.Scale;
public const int MouseScrollDelta = 120; public const int MouseScrollDelta = 120;
private Point mousePosition; private Point mousePosition;
@ -84,17 +85,17 @@ public class InputManager
private Modifiers keyboardMods = 0; private Modifiers keyboardMods = 0;
private readonly HashSet<Keys> pressedKeys = new(); private readonly HashSet<Keys> pressedKeys = new();
private readonly Game _game; private readonly Capy64 _game;
private readonly EventEmitter _eventEmitter; private readonly EventEmitter _eventEmitter;
public InputManager(Game game, EventEmitter eventManager) public InputManager(Capy64 game, EventEmitter eventManager)
{ {
_game = game; _game = game;
_eventEmitter = eventManager; _eventEmitter = eventManager;
_game.Window.KeyDown += OnKeyDown; /*_game.Window.KeyDown += OnKeyDown;
_game.Window.KeyUp += OnKeyUp; _game.Window.KeyUp += OnKeyUp;
_game.Window.TextInput += OnTextInput; _game.Window.TextInput += OnTextInput;*/
var mouseState = Mouse.GetState(); var mouseState = Mouse.GetState();
vMouseScroll = mouseState.ScrollWheelValue; vMouseScroll = mouseState.ScrollWheelValue;
@ -108,12 +109,36 @@ public class InputManager
UpdateGamePad(GamePad.GetState(PlayerIndex.One), IsActive); UpdateGamePad(GamePad.GetState(PlayerIndex.One), IsActive);
} }
public void UpdateMouse(MouseState state, bool isActive) public void UpdateMouseSDL(SDL.SDL_Event ev)
{
var position = new Point(ev.button.x, ev.button.y);
var rawPosition = position - new Point(LegacyEntry.Instance.Borders.Left, LegacyEntry.Instance.Borders.Top);
var pos = new Point((int)(rawPosition.X / WindowScale), (int)(rawPosition.Y / WindowScale)) + new Point(1, 1);
if (pos.X < 1 || pos.Y < 1 || pos.X > (_game.Width) || pos.Y > _game.Height)
return;
if (pos != mousePosition)
{
mousePosition = pos;
_eventEmitter.RaiseMouseMove(new()
{
Position = mousePosition,
PressedButtons = mouseButtonStates
.Where(q => q.Value == ButtonState.Pressed)
.Select(q => (int)q.Key)
.ToArray()
});
}
}
private void UpdateMouse(MouseState state, bool isActive)
{ {
if (!isActive) if (!isActive)
return; return;
var rawPosition = state.Position - new Point(Capy64.Instance.Borders.Left, Capy64.Instance.Borders.Top); var rawPosition = state.Position - new Point(LegacyEntry.Instance.Borders.Left, LegacyEntry.Instance.Borders.Top);
var pos = new Point((int)(rawPosition.X / WindowScale), (int)(rawPosition.Y / WindowScale)) + new Point(1, 1); var pos = new Point((int)(rawPosition.X / WindowScale), (int)(rawPosition.Y / WindowScale)) + new Point(1, 1);
if (pos.X < 1 || pos.Y < 1 || pos.X > Texture.Width || pos.Y > Texture.Height) if (pos.X < 1 || pos.Y < 1 || pos.X > Texture.Width || pos.Y > Texture.Height)

View file

@ -28,7 +28,7 @@ public class DiscordIntegration : IComponent
public readonly bool Enabled; public readonly bool Enabled;
private readonly IConfiguration _configuration; private readonly IConfiguration _configuration;
public DiscordIntegration(Capy64 game) public DiscordIntegration(LegacyEntry game)
{ {
_configuration = game.Configuration; _configuration = game.Configuration;
@ -42,7 +42,7 @@ public class DiscordIntegration : IComponent
Client.OnReady += OnReady; Client.OnReady += OnReady;
Capy64.Instance.Discord = this; LegacyEntry.Instance.Discord = this;
if (Enabled) if (Enabled)
Client.Initialize(); Client.Initialize();
@ -62,7 +62,7 @@ public class DiscordIntegration : IComponent
Assets = new Assets() Assets = new Assets()
{ {
LargeImageKey = "image_large", LargeImageKey = "image_large",
LargeImageText = "Capy64 " + Capy64.Version, LargeImageText = "Capy64 " + LegacyEntry.Version,
SmallImageKey = "image_small" SmallImageKey = "image_small"
} }
}); });

338
Capy64/LegacyEntry.cs Normal file
View file

@ -0,0 +1,338 @@
// 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 Capy64.Core;
using Capy64.Eventing;
using Capy64.Extensions;
using Capy64.Integrations;
using Capy64.PluginManager;
using Capy64.Runtime;
using Microsoft.Extensions.Configuration;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using MonoGame.Extended;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.InteropServices;
using static Capy64.Utils;
namespace Capy64;
public enum EngineMode
{
Classic,
Free
}
public class LegacyEntry : Game
{
public const string Version = "1.1.0-beta";
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 static readonly EngineMode EngineMode = EngineMode.Classic;
public const int ClassicTickrate = 30;
public const int FreeTickrate = 60;
}
public static readonly string AssemblyPath = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
public static readonly string AssetsPath = Path.Combine(AssemblyPath, "Assets");
public static string AppDataPath
{
get
{
string baseDir =
RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ?
Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData,
Environment.SpecialFolderOption.Create) :
RuntimeInformation.IsOSPlatform(OSPlatform.Linux) ?
Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData,
Environment.SpecialFolderOption.Create) :
RuntimeInformation.IsOSPlatform(OSPlatform.OSX) ?
Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData,
Environment.SpecialFolderOption.Create) :
"./";
return Path.Combine(baseDir, "Capy64");
}
}
public static LegacyEntry Instance { get; private set; }
public LegacyEntry Game => this;
public EngineMode EngineMode { get; private set; } = EngineMode.Classic;
public IList<IComponent> NativePlugins { get; private set; }
public IList<IComponent> Plugins { get; private set; }
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; }
public Eventing.EventEmitter EventEmitter { get; private set; }
public DiscordIntegration Discord { get; set; }
public int TickRate => tickrate;
public IConfiguration Configuration { get; private set; }
public Color BorderColor { get; set; } = Color.Black;
public Borders Borders = new()
{
Top = 0,
Bottom = 0,
Left = 0,
Right = 0,
};
public SpriteBatch SpriteBatch;
private readonly InputManager _inputManager;
private RenderTarget2D renderTarget;
private readonly GraphicsDeviceManager _graphics;
private ulong _totalTicks = 0;
private int tickrate = 0;
private int everyTick => 60 / tickrate;
public LegacyEntry()
{
Instance = this;
_graphics = new GraphicsDeviceManager(this);
//Content.RootDirectory = "Content";
IsMouseVisible = true;
EventEmitter = new();
_inputManager = new(null, EventEmitter);
Drawing = new();
}
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;
}
EngineMode = mode;
UpdateSize(true);
}
public void UpdateSize(bool resize = true)
{
if (resize)
{
_graphics.PreferredBackBufferWidth = (int)(Width * Scale) + Borders.Left + Borders.Right;
_graphics.PreferredBackBufferHeight = (int)(Height * Scale) + Borders.Top + Borders.Bottom;
_graphics.ApplyChanges();
}
renderTarget = new RenderTarget2D(
GraphicsDevice,
Width,
Height,
false,
GraphicsDevice.PresentationParameters.BackBufferFormat,
DepthFormat.Depth24, 0, RenderTargetUsage.PreserveContents);
Drawing.Canvas = renderTarget;
_inputManager.Texture = renderTarget;
EventEmitter.RaiseScreenSizeChange();
}
private void OnWindowSizeChange(object sender, EventArgs e)
{
if (EngineMode == EngineMode.Classic)
{
UpdateSize(true);
return;
}
var bounds = Window.ClientBounds;
Width = (int)(bounds.Width / Scale);
Height = (int)(bounds.Height / Scale);
if (Window.IsMaximized())
{
var vertical = bounds.Height - (Height * Scale);
var horizontal = bounds.Width - (Width * Scale);
Borders.Top = (int)Math.Floor(vertical / 2d);
Borders.Bottom = (int)Math.Ceiling(vertical / 2d);
Borders.Left = (int)Math.Floor(horizontal / 2d);
Borders.Right = (int)Math.Ceiling(horizontal / 2d);
UpdateSize(false);
}
else
{
ResetBorder();
UpdateSize();
}
}
private void ResetBorder()
{
var size = (int)(Scale * DefaultParameters.BorderMultiplier);
Borders = new Borders
{
Top = size,
Bottom = size,
Left = size,
Right = size
};
}
protected override void Initialize()
{
var configBuilder = new ConfigurationBuilder();
var settingsPath = Path.Combine(AppDataPath, "settings.json");
if (!Directory.Exists(AppDataPath))
{
Directory.CreateDirectory(AppDataPath);
}
if (!File.Exists(settingsPath))
{
File.Copy(Path.Combine(AssetsPath, "default.json"), settingsPath);
}
configBuilder.AddJsonFile(Path.Combine(AssetsPath, "default.json"), false);
configBuilder.AddJsonFile(settingsPath, false);
Configuration = configBuilder.Build();
Window.Title = "Capy64 " + Version;
Scale = Configuration.GetValue("Window:Scale", DefaultParameters.Scale);
ResetBorder();
UpdateSize();
Window.AllowUserResizing = true;
Window.ClientSizeChanged += OnWindowSizeChange;
InactiveSleepTime = new TimeSpan(0);
SetEngineMode(Configuration.GetValue<EngineMode>("EngineMode", DefaultParameters.EngineMode));
Audio = new Audio();
NativePlugins = GetNativePlugins();
var safeMode = Configuration.GetValue("SafeMode", false);
if (!safeMode)
Plugins = PluginLoader.LoadAllPlugins(Path.Combine(AppDataPath, "plugins"));
EventEmitter.RaiseInit();
base.Initialize();
}
private List<IComponent> GetNativePlugins()
{
var iType = typeof(IComponent);
var types = AppDomain.CurrentDomain.GetAssemblies()
.SelectMany(s => s.GetTypes())
.Where(p => iType.IsAssignableFrom(p) && !p.IsInterface);
var plugins = new List<IComponent>();
foreach (var type in types)
{
var instance = (IComponent)Activator.CreateInstance(type, this);
plugins.Add(instance);
}
return plugins;
}
protected override void LoadContent()
{
SpriteBatch = new SpriteBatch(GraphicsDevice);
}
protected override void Update(GameTime gameTime)
{
Drawing.Begin();
// Register user input
_inputManager.Update(IsActive);
EventEmitter.RaiseTick(new()
{
GameTime = gameTime,
TotalTicks = _totalTicks,
IsActiveTick = (int)_totalTicks % everyTick == 0,
});
Drawing.End();
_totalTicks++;
base.Update(gameTime);
}
protected override void Draw(GameTime gameTime)
{
SpriteBatch.Begin(SpriteSortMode.Deferred, BlendState.AlphaBlend, SamplerState.PointClamp);
GraphicsDevice.Clear(BorderColor);
SpriteBatch.DrawRectangle(renderTarget.Bounds.Location.ToVector2() + new Vector2(Borders.Left, Borders.Top),
new Size2(renderTarget.Bounds.Width * Scale, renderTarget.Bounds.Height * Scale), Color.Black,
Math.Min(renderTarget.Bounds.Width, renderTarget.Bounds.Height), 0);
SpriteBatch.Draw(renderTarget, new(Borders.Left, Borders.Top), null, Color.White, 0f, Vector2.Zero, Scale,
SpriteEffects.None, 0);
EventEmitter.RaiseOverlay(new()
{
GameTime = gameTime,
TotalTicks = _totalTicks,
});
SpriteBatch.End();
base.Draw(gameTime);
}
}

View file

@ -46,7 +46,7 @@ internal class PluginLoader
{ {
if (typeof(IComponent).IsAssignableFrom(type)) if (typeof(IComponent).IsAssignableFrom(type))
{ {
IComponent result = Activator.CreateInstance(type, Capy64.Instance) as IComponent; IComponent result = Activator.CreateInstance(type, LegacyEntry.Instance) as IComponent;
plugins.Add(result); plugins.Add(result);
} }
} }

View file

@ -17,13 +17,13 @@ using Capy64;
if (args.Length > 0 && args[0] == "sdl") if (args.Length > 0 && args[0] == "sdl")
{ {
using var game = new SDLEntry(); using var game = new Capy64.Capy64();
game.Run(); game.Run();
} }
else else
{ {
using var game = new Capy64.Capy64(); using var game = new Capy64.LegacyEntry();
game.Run(); game.Run();
} }

View file

@ -25,8 +25,8 @@ public class AudioLib : IComponent
{ {
private const int queueLimit = 8; private const int queueLimit = 8;
private static Capy64 _game; private static LegacyEntry _game;
public AudioLib(Capy64 game) public AudioLib(LegacyEntry game)
{ {
_game = game; _game = game;
_game.EventEmitter.OnClose += OnClose; _game.EventEmitter.OnClose += OnClose;

View file

@ -29,8 +29,8 @@ public class EventLib : IComponent
private static bool FrozenTaskAwaiter = false; private static bool FrozenTaskAwaiter = false;
private static Capy64 _game; private static LegacyEntry _game;
public EventLib(Capy64 game) public EventLib(LegacyEntry game)
{ {
_game = game; _game = game;
} }

View file

@ -26,7 +26,7 @@ namespace Capy64.Runtime.Libraries;
public class FileSystemLib : IComponent public class FileSystemLib : IComponent
{ {
public static string DataPath = Path.Combine(Capy64.AppDataPath, "data"); public static string DataPath = Path.Combine(LegacyEntry.AppDataPath, "data");
public FileSystemLib() public FileSystemLib()
{ {
@ -111,7 +111,7 @@ public class FileSystemLib : IComponent
new(), // NULL new(), // NULL
}; };
public FileSystemLib(Capy64 _) { } public FileSystemLib(LegacyEntry _) { }
public void LuaInit(Lua state) public void LuaInit(Lua state)
{ {

View file

@ -28,8 +28,8 @@ namespace Capy64.Runtime.Libraries;
public class GPULib : IComponent public class GPULib : IComponent
{ {
private static Capy64 _game; private static LegacyEntry _game;
public GPULib(Capy64 game) public GPULib(LegacyEntry game)
{ {
_game = game; _game = game;
} }
@ -657,7 +657,7 @@ public class GPULib : IComponent
Texture2D texture; Texture2D texture;
try try
{ {
texture = Texture2D.FromFile(Capy64.Instance.Drawing.Canvas.GraphicsDevice, path); texture = Texture2D.FromFile(LegacyEntry.Instance.Drawing.Canvas.GraphicsDevice, path);
} }
catch (Exception e) catch (Exception e)
{ {

View file

@ -30,12 +30,12 @@ namespace Capy64.Runtime.Libraries;
#nullable enable #nullable enable
public class HTTPLib : IComponent public class HTTPLib : IComponent
{ {
private static Capy64 _game = null!; private static LegacyEntry _game = null!;
private static HttpClient _httpClient = null!; private static HttpClient _httpClient = null!;
private static long _requestId; private static long _requestId;
public static readonly HashSet<WebSocketClient.Client> WebSocketConnections = new(); public static readonly HashSet<WebSocketClient.Client> WebSocketConnections = new();
public static readonly string UserAgent = $"Capy64/{Capy64.Version}"; public static readonly string UserAgent = $"Capy64/{LegacyEntry.Version}";
private static IConfiguration _configuration = null!; private static IConfiguration _configuration = null!;
private readonly LuaRegister[] Library = new LuaRegister[] private readonly LuaRegister[] Library = new LuaRegister[]
@ -57,7 +57,7 @@ public class HTTPLib : IComponent
}, },
new(), new(),
}; };
public HTTPLib(Capy64 game) public HTTPLib(LegacyEntry game)
{ {
_game = game; _game = game;
_requestId = 0; _requestId = 0;

View file

@ -24,8 +24,8 @@ namespace Capy64.Runtime.Libraries;
public class MachineLib : IComponent public class MachineLib : IComponent
{ {
private static Capy64 _game; private static LegacyEntry _game;
public MachineLib(Capy64 game) public MachineLib(LegacyEntry game)
{ {
_game = game; _game = game;
} }
@ -109,7 +109,7 @@ public class MachineLib : IComponent
{ {
var L = Lua.FromIntPtr(state); var L = Lua.FromIntPtr(state);
var currentTitle = Capy64.Instance.Window.Title; var currentTitle = LegacyEntry.Instance.Window.Title;
if (!L.IsNoneOrNil(1)) if (!L.IsNoneOrNil(1))
{ {
@ -117,12 +117,12 @@ public class MachineLib : IComponent
if (string.IsNullOrEmpty(newTitle)) if (string.IsNullOrEmpty(newTitle))
{ {
newTitle = "Capy64 " + Capy64.Version; newTitle = "Capy64 " + LegacyEntry.Version;
} }
newTitle = newTitle[..Math.Min(newTitle.Length, 256)]; newTitle = newTitle[..Math.Min(newTitle.Length, 256)];
Capy64.Instance.Window.Title = newTitle; LegacyEntry.Instance.Window.Title = newTitle;
} }
L.PushString(currentTitle); L.PushString(currentTitle);
@ -157,7 +157,7 @@ public class MachineLib : IComponent
{ {
var L = Lua.FromIntPtr(state); var L = Lua.FromIntPtr(state);
L.PushString("Capy64 " + Capy64.Version); L.PushString("Capy64 " + LegacyEntry.Version);
return 1; return 1;
} }
@ -171,7 +171,7 @@ public class MachineLib : IComponent
try try
{ {
Capy64.Instance.Discord.SetPresence(details, dstate); LegacyEntry.Instance.Discord.SetPresence(details, dstate);
L.PushBoolean(true); L.PushBoolean(true);
} }
catch (Exception e) catch (Exception e)

View file

@ -49,11 +49,11 @@ internal class TermLib : IComponent
public static Color BackgroundColor { get; set; } public static Color BackgroundColor { get; set; }
private static Char?[] CharGrid; private static Char?[] CharGrid;
private static Capy64 _game; private static LegacyEntry _game;
private static bool cursorState = false; private static bool cursorState = false;
private static bool enableCursor = true; private static bool enableCursor = true;
private static Texture2D cursorTexture; private static Texture2D cursorTexture;
public TermLib(Capy64 game) public TermLib(LegacyEntry game)
{ {
_game = game; _game = game;
@ -317,7 +317,7 @@ internal class TermLib : IComponent
{ {
var realpos = ToRealPos(CursorPosition - Vector2.One); var realpos = ToRealPos(CursorPosition - Vector2.One);
var charpos = (realpos * _game.Scale) + ((CharOffset + new Vector2(0, 2)) * _game.Scale); var charpos = (realpos * _game.Scale) + ((CharOffset + new Vector2(0, 2)) * _game.Scale);
charpos += new Vector2(Capy64.Instance.Borders.Left, Capy64.Instance.Borders.Top); charpos += new Vector2(LegacyEntry.Instance.Borders.Left, LegacyEntry.Instance.Borders.Top);
_game.Game.SpriteBatch.Draw(cursorTexture, charpos, null, ForegroundColor, 0f, Vector2.Zero, _game.Scale, SpriteEffects.None, 0); _game.Game.SpriteBatch.Draw(cursorTexture, charpos, null, ForegroundColor, 0f, Vector2.Zero, _game.Scale, SpriteEffects.None, 0);
} }
} }

View file

@ -50,11 +50,11 @@ class TimerLib : IComponent
new(), new(),
}; };
private static Capy64 _game; private static LegacyEntry _game;
private static uint _timerId = 0; private static uint _timerId = 0;
private static readonly ConcurrentDictionary<uint, Timer> timers = new(); private static readonly ConcurrentDictionary<uint, Timer> timers = new();
public TimerLib(Capy64 game) public TimerLib(LegacyEntry game)
{ {
_game = game; _game = game;
@ -122,7 +122,7 @@ class TimerLib : IComponent
timers[timerId] = new Timer timers[timerId] = new Timer
{ {
RemainingTicks = (int)(delay * Capy64.Instance.TickRate) RemainingTicks = (int)(delay * LegacyEntry.Instance.TickRate)
}; };
L.PushInteger(timerId); L.PushInteger(timerId);
@ -141,7 +141,7 @@ class TimerLib : IComponent
timers[timerId] = new Timer timers[timerId] = new Timer
{ {
RemainingTicks = (int)(delay * Capy64.Instance.TickRate), RemainingTicks = (int)(delay * LegacyEntry.Instance.TickRate),
Task = task, Task = task,
}; };

View file

@ -72,8 +72,8 @@ public class LuaState : IDisposable
private void InitPlugins() private void InitPlugins()
{ {
var allPlugins = new List<IComponent>(Capy64.Instance.NativePlugins); var allPlugins = new List<IComponent>(LegacyEntry.Instance.NativePlugins);
allPlugins.AddRange(Capy64.Instance.Plugins); allPlugins.AddRange(LegacyEntry.Instance.Plugins);
foreach (var plugin in allPlugins) foreach (var plugin in allPlugins)
{ {
plugin.LuaInit(Thread); plugin.LuaInit(Thread);

View file

@ -25,8 +25,8 @@ public class ObjectManager : IComponent
{ {
private static readonly ConcurrentDictionary<nint, object> _objects = new(); private static readonly ConcurrentDictionary<nint, object> _objects = new();
private static Capy64 _game; private static LegacyEntry _game;
public ObjectManager(Capy64 game) public ObjectManager(LegacyEntry game)
{ {
_game = game; _game = game;
_game.EventEmitter.OnClose += OnClose; _game.EventEmitter.OnClose += OnClose;

View file

@ -88,7 +88,7 @@ public class FileHandle : IComponent
new(), new(),
}; };
public FileHandle(Capy64 _) { } public FileHandle(LegacyEntry _) { }
public void LuaInit(Lua L) public void LuaInit(Lua L)
{ {

View file

@ -66,8 +66,8 @@ public class GPUBufferMeta : IComponent
new(), new(),
}; };
private static Capy64 _game; private static LegacyEntry _game;
public GPUBufferMeta(Capy64 game) public GPUBufferMeta(LegacyEntry game)
{ {
_game = game; _game = game;
} }

View file

@ -29,8 +29,8 @@ public class Socket : IDisposable
public class SocketLib : IComponent public class SocketLib : IComponent
{ {
private static Capy64 _game = null!; private static LegacyEntry _game = null!;
public SocketLib(Capy64 game) public SocketLib(LegacyEntry game)
{ {
_game = game; _game = game;
} }

View file

@ -21,8 +21,8 @@ namespace Capy64.Runtime.Objects;
public class TaskMeta : IComponent public class TaskMeta : IComponent
{ {
private static Capy64 _game; private static LegacyEntry _game;
public TaskMeta(Capy64 game) public TaskMeta(LegacyEntry game)
{ {
_game = game; _game = game;
} }

View file

@ -73,7 +73,7 @@ public class WebSocketClient : IComponent
new(), new(),
}; };
public WebSocketClient(Capy64 _) { } public WebSocketClient(LegacyEntry _) { }
public void LuaInit(Lua L) public void LuaInit(Lua L)
{ {
@ -146,7 +146,7 @@ public class WebSocketClient : IComponent
.ContinueWith(async task => .ContinueWith(async task =>
{ {
await task; await task;
Capy64.Instance.LuaRuntime.QueueEvent("websocket_close", LK => LegacyEntry.Instance.LuaRuntime.QueueEvent("websocket_close", LK =>
{ {
LK.PushInteger(client.RequestId); LK.PushInteger(client.RequestId);

View file

@ -32,8 +32,8 @@ internal class RuntimeManager : IComponent
private static bool close = false; private static bool close = false;
private static bool inPanic = false; private static bool inPanic = false;
private static Capy64 _game; private static LegacyEntry _game;
public RuntimeManager(Capy64 game) public RuntimeManager(LegacyEntry game)
{ {
_game = game; _game = game;
@ -124,7 +124,7 @@ internal class RuntimeManager : IComponent
luaState.Thread.PushCFunction(L_Exit); luaState.Thread.PushCFunction(L_Exit);
luaState.Thread.SetGlobal("exit"); luaState.Thread.SetGlobal("exit");
var status = luaState.Thread.LoadFile(Path.Combine(Capy64.AssetsPath, "Lua/bios.lua")); var status = luaState.Thread.LoadFile(Path.Combine(LegacyEntry.AssetsPath, "Lua/bios.lua"));
if (status != LuaStatus.OK) if (status != LuaStatus.OK)
{ {
throw new LuaException(luaState.Thread.ToString(-1)); throw new LuaException(luaState.Thread.ToString(-1));
@ -185,7 +185,7 @@ internal class RuntimeManager : IComponent
private void LoadFirmware() private void LoadFirmware()
{ {
var firmwareContent = File.ReadAllText(Path.Combine(Capy64.AssetsPath, "Lua/firmware.lua")); var firmwareContent = File.ReadAllText(Path.Combine(LegacyEntry.AssetsPath, "Lua/firmware.lua"));
var errored = luaState.Thread.DoString(firmwareContent); var errored = luaState.Thread.DoString(firmwareContent);
if (errored) if (errored)
{ {
@ -212,10 +212,10 @@ internal class RuntimeManager : IComponent
public static void InstallOS(bool force = false) public static void InstallOS(bool force = false)
{ {
var installedFilePath = Path.Combine(Capy64.AppDataPath, ".installed"); var installedFilePath = Path.Combine(LegacyEntry.AppDataPath, ".installed");
if (!File.Exists(installedFilePath) || force) if (!File.Exists(installedFilePath) || force)
{ {
FileSystemLib.CopyDirectory(Path.Combine(Capy64.AssetsPath, "Lua/CapyOS"), FileSystemLib.DataPath, true, true); FileSystemLib.CopyDirectory(Path.Combine(LegacyEntry.AssetsPath, "Lua/CapyOS"), FileSystemLib.DataPath, true, true);
File.Create(installedFilePath).Dispose(); File.Create(installedFilePath).Dispose();
} }
} }

View file

@ -1,171 +0,0 @@
// 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.
namespace Capy64;
using System;
using System.IO;
using System.Reflection;
using System.Runtime.InteropServices;
using static global::Capy64.Utils;
using static SDL2.SDL;
public class SDLEntry : IDisposable
{
public const string Version = "1.1.0-beta";
public nint Window { get; private set; } = 0;
public nint Renderer { get; private set; } = 0;
public nint VideoSurface { get; private set; } = 0;
public int WindowWidth { get; private set; }
public int WindowHeight { get; private set; }
public int Width { get; set; } = DefaultParameters.Width;
public int Height { get; set; } = DefaultParameters.Height;
public float Scale { get; set; } = DefaultParameters.Scale;
public uint BorderColor { get; set; } = 0x0;
public Borders Borders
{
get => _borders;
set
{
_borders = value;
}
}
private SDL_Rect _bordersRect;
private Borders _borders;
public static readonly string AssemblyPath = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
public static readonly string AssetsPath = Path.Combine(AssemblyPath, "Assets");
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 static readonly EngineMode EngineMode = EngineMode.Classic;
public const int ClassicTickrate = 30;
public const int FreeTickrate = 60;
}
public static string AppDataPath
{
get
{
string baseDir =
RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ?
Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData,
Environment.SpecialFolderOption.Create) :
RuntimeInformation.IsOSPlatform(OSPlatform.Linux) ?
Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData,
Environment.SpecialFolderOption.Create) :
RuntimeInformation.IsOSPlatform(OSPlatform.OSX) ?
Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData,
Environment.SpecialFolderOption.Create) :
"./";
return Path.Combine(baseDir, "Capy64");
}
}
public SDLEntry()
{
Borders = new()
{
Top = 0,
Bottom = 0,
Left = 0,
Right = 0,
};
WindowWidth = (int)(Width * Scale) + Borders.Left + Borders.Right;
WindowHeight = (int)(Height * Scale) + Borders.Top + Borders.Bottom;
}
public void Run()
{
#if DEBUG
SDL_SetHint(SDL_HINT_WINDOWS_DISABLE_THREAD_NAMING, "1");
#endif
if (SDL_Init(SDL_INIT_EVERYTHING) != 0)
{
Console.WriteLine(SDL_GetError());
return;
}
Window = SDL_CreateWindow("Capy64 " + Version,
SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED,
WindowWidth, WindowHeight,
SDL_WindowFlags.SDL_WINDOW_OPENGL);
if (Window == nint.Zero)
{
Console.WriteLine(SDL_GetError());
return;
}
Renderer = SDL_CreateRenderer(Window,
0,
SDL_RendererFlags.SDL_RENDERER_ACCELERATED | SDL_RendererFlags.SDL_RENDERER_PRESENTVSYNC);
if (Renderer == nint.Zero)
{
Console.WriteLine(SDL_GetError());
return;
}
VideoSurface = SDL_CreateRGBSurfaceWithFormat(0, Width, Height, 32, SDL_PIXELFORMAT_ARGB8888);
var running = true;
while (running)
{
while (SDL_PollEvent(out var ev) != 0)
{
switch (ev.type)
{
case SDL_EventType.SDL_QUIT:
running = false;
break;
case SDL_EventType.SDL_KEYDOWN:
if (ev.key.keysym.scancode == SDL_Scancode.SDL_SCANCODE_ESCAPE)
running = false;
unsafe
{
var pitch = ((SDL_Surface*)VideoSurface)->pitch;
((uint*)((SDL_Surface*)VideoSurface)->pixels)[10 + 10 * pitch / 4] = 0xFFFF00FF;
}
break;
}
}
SDL_RenderClear(Renderer);
var texture = SDL_CreateTextureFromSurface(Renderer, VideoSurface);
SDL_RenderCopy(Renderer, texture, 0, 0);
SDL_DestroyTexture(texture);
SDL_RenderPresent(Renderer);
}
}
public void Dispose()
{
SDL_DestroyRenderer(Renderer);
SDL_DestroyWindow(Window);
SDL_Quit();
}
}

View file

@ -5,8 +5,8 @@ namespace ExamplePlugin;
public class MyPlugin : IComponent public class MyPlugin : IComponent
{ {
private static Capy64.Capy64 _game; private static Capy64.LegacyEntry _game;
public MyPlugin(Capy64.Capy64 game) public MyPlugin(Capy64.LegacyEntry game)
{ {
_game = game; _game = game;
} }