using System ;
using DotSDL.Sdl ;
namespace DotSDL.Graphics {
/// <summary>
/// Represents an SDL window.
/// </summary>
public class SdlWindow {
private readonly SdlInit _ sdlInit = SdlInit . Instance ;
private readonly IntPtr _ window ;
private readonly IntPtr _ renderer ;
private readonly IntPtr _ texture ;
private Canvas _ canvas ;
private bool _ running ;
private uint _ nextVideoUpdate ;
private uint _ nextGameUpdate ;
/// <summary>The width of the user window.</summary>
public int WindowWidth { get ; }
/// <summary>The height of the user window.</summary>
public int WindowHeight { get ; }
/// <summary>The width of the internal texture used by this <see cref="SdlWindow"/>.</summary>
public int TextureWidth { get ; }
/// <summary>The height of the internal texture used by this <see cref="SdlWindow"/>.</summary>
public int TextureHeight { get ; }
/// <summary>The amount of time, in milliseconds, from when the application was started.</summary>
public uint TicksElapsed = > Timer . GetTicks ( ) ;
/// <summary>Gets or sets the amount of time, in milliseconds, between video updates.</summary>
public uint VideoUpdateTicks { get ; set ; }
/// <summary>Gets or sets the amount of time, in milliseconds, between game (logic) updates.</summary>
public uint GameUpdateTicks { get ; set ; }
/// <summary>
/// Indicates that the window manager should position the window. To place the window on a specific display, use the <see cref="WindowPosCenteredDisplay"/> function.
/// </summary>
public const int WindowPosUndefined = 0x1FFF0000 ;
/// <summary>
/// Calculates a value that allows the window to be placed on a specific display, with its exact position determined by the window manager.
/// </summary>
/// <param name="display">The index of the display to place the window on.</param>
/// <returns>A coordinate value that should be passed to the <see cref="SdlWindow"/> constructor.</returns>
public static int WindowPosUndefinedDisplay ( uint display ) {
return ( int ) ( WindowPosUndefined | display ) ;
}
/// <summary>
/// Indicates that the window should be in the center of the screen. To center the window on a specific display, use the <see cref="WindowPosCenteredDisplay"/> function.
/// </summary>
public const int WindowPosCentered = 0x2FFF0000 ;
/// <summary>
/// Calculates a value that allows the window to be placed in the center of a specified display.
/// </summary>
/// <param name="display">The index of the display to place the window on.</param>
/// <returns>A coordinate value that should be passed to the <see cref="SdlWindow"/> constructor.</returns>
public static int WindowPosCenteredDisplay ( uint display ) {
return ( int ) ( WindowPosCentered | display ) ;
}
/// <summary>
/// Creates a new <see cref="SdlWindow"/>.
/// </summary>
/// <param name="title">The text that is displayed on the window's title bar.</param>
/// <param name="position">A <see cref="Point"/> representing the starting position of the window. The X and Y coordinates of the Point can be set to <see cref="WindowPosUndefined"/> or <see cref="WindowPosCentered"/>.</param>
/// <param name="windowWidth">The width of the window.</param>
/// <param name="windowHeight">The height of the window.</param>
public SdlWindow ( string title , Point position , int windowWidth , int windowHeight ) : this ( title , position , windowWidth , windowHeight , windowWidth , windowHeight ) { }
/// <summary>
/// Creates a new <see cref="SdlWindow"/>.
/// </summary>
/// <param name="title">The text that is displayed on the window's title bar.</param>
/// <param name="position">A <see cref="Point"/> representing the starting position of the window. The X and Y coordinates of the Point can be set to <see cref="WindowPosUndefined"/> or <see cref="WindowPosCentered"/>.</param>
/// <param name="windowWidth">The width of the window.</param>
/// <param name="windowHeight">The height of the window.</param>
/// <param name="textureWidth">The width of the window's texture.</param>
/// <param name="textureHeight">The height of the window's texture.</param>
public SdlWindow ( string title , Point position , int windowWidth , int windowHeight , int textureWidth , int textureHeight ) {
_ sdlInit . InitSubsystem ( Init . SubsystemFlags . Video ) ;
_ window = Video . CreateWindow ( title , position . X , position . Y , windowWidth , windowHeight , Video . WindowFlags . Hidden ) ;
_ renderer = Render . CreateRenderer ( _ window , - 1 , Render . RendererFlags . Accelerated ) ;
_ texture = Render . CreateTexture ( _ renderer , Pixels . PixelFormatArgb8888 , Render . TextureAccess . Streaming , textureWidth , textureHeight ) ;
_ canvas = new Canvas ( textureWidth , textureHeight ) ;
WindowWidth = windowWidth ;
WindowHeight = windowHeight ;
TextureWidth = textureWidth ;
TextureHeight = textureHeight ;
}
/// <summary>
/// Handles calling the user draw function and passing the CLR objects to SDL2.
/// </summary>
private unsafe void BaseDraw ( ) {
OnDraw ( ref _ canvas ) ; // Call the overridden Draw function.
fixed ( void * pixelsPtr = _ canvas . Pixels ) {
var ptr = ( IntPtr ) pixelsPtr ;
Render . UpdateTexture ( _ texture , IntPtr . Zero , ptr , TextureWidth * 4 ) ;
}
Render . RenderCopy ( _ renderer , _ texture , IntPtr . Zero , IntPtr . Zero ) ;
Render . RenderPresent ( _ renderer ) ;
}
/// <summary>
/// Handles setting up the <see cref="SdlWindow"/>.
/// </summary>
private void BaseLoad ( ) {
OnLoad ( ) ; // Call the overridden Load function.
}
/// <summary>
/// Handles updating the application logic for the <see cref="SdlWindow"/>.
/// </summary>
private void BaseUpdate ( ) {
OnUpdate ( ) ; // Call the overridden Update function.
}
/// <summary>
/// A game loop that calls the <see cref="SdlWindow"/> update and draw functions.
/// </summary>
private void Loop ( ) {
_ running = true ;
while ( _ running ) {
BaseUpdate ( ) ;
BaseDraw ( ) ;
}
}
/// <summary>
/// Fired every time the window is drawn to.
/// </summary>
/// <param name="canvas">The active canvas for the window.</param>
protected virtual void OnDraw ( ref Canvas canvas ) { }
/// <summary>
/// Fired before the window is shown.
/// </summary>
protected virtual void OnLoad ( ) { }
/// <summary>
/// Fired every time the application logic update runs.
/// </summary>
protected virtual void OnUpdate ( ) { }
/// <summary>
/// Displays the window and begins executing code that's associated with it.
/// </summary>
public void Start ( ) {
BaseLoad ( ) ;
Video . ShowWindow ( _ window ) ;
Loop ( ) ;
}
}
}