Browse Source

Unified the drawing routines.

* Moved both the Shown and ZOrder properties to the Canvas class.
    * Sprites and Backgrounds are now both considered when doing z-order
      checks. As such, sprites can now be drawn under backgrounds. This will
      likely need more optimization.
mouse
Ian Burgmyer 5 years ago
parent
commit
1253e3017b
  1. 2
      DotSDL/Graphics/Background.cs
  2. 11
      DotSDL/Graphics/Canvas.cs
  3. 147
      DotSDL/Graphics/SdlWindow.cs

2
DotSDL/Graphics/Background.cs

@ -30,7 +30,7 @@ namespace DotSDL.Graphics {
// TODO: Might be able to make this faster by leveraging memcpy(). Need to benchmark it. // TODO: Might be able to make this faster by leveraging memcpy(). Need to benchmark it.
unsafe { unsafe {
var copySize = Width * Height * 4; // Width x Height at 4 bytes per pixel. var copySize = Width * Height * 4; // Width x Height at 4 bytes per pixel.
Render.LockTexture(Texture, IntPtr.Zero, out var pixels, out var _); Render.LockTexture(Texture, IntPtr.Zero, out var pixels, out _);
Buffer.MemoryCopy(GetCanvasPointer().ToPointer(), pixels, copySize, copySize); Buffer.MemoryCopy(GetCanvasPointer().ToPointer(), pixels, copySize, copySize);
Render.UnlockTexture(Texture); Render.UnlockTexture(Texture);
} }

11
DotSDL/Graphics/Canvas.cs

@ -153,6 +153,17 @@ namespace DotSDL.Graphics {
} }
} }
/// <summary>
/// <c>true</c> if the <see cref="Canvas"/> should be drawn to the screen, otherwise <c>false</c>.
/// </summary>
public bool Shown { get; set; } = true;
/// <summary>
/// The order in which the canvas is drawn. Lower numbered <see cref="Canvas"/> instances are drawn first
/// and will appear on the bottom. This number can be negative.
/// </summary>
public int ZOrder { get; set; }
/// <summary> /// <summary>
/// Sets the section of the <see cref="Canvas"/> that should be drawn. If the size values are set to 0, the /// Sets the section of the <see cref="Canvas"/> that should be drawn. If the size values are set to 0, the
/// <see cref="Canvas"/> will fill as much of its containing object as possible. /// <see cref="Canvas"/> will fill as much of its containing object as possible.

147
DotSDL/Graphics/SdlWindow.cs

@ -31,6 +31,8 @@ namespace DotSDL.Graphics {
private float _nextGameUpdate; private float _nextGameUpdate;
private float _updateDelta; private float _updateDelta;
private List<Canvas> _drawList = new List<Canvas>();
private ScalingQuality _scalingQuality = ScalingQuality.Nearest; private ScalingQuality _scalingQuality = ScalingQuality.Nearest;
/// <summary> /// <summary>
@ -228,6 +230,7 @@ namespace DotSDL.Graphics {
BlendMode = BlendMode.None BlendMode = BlendMode.None
} }
}; };
Background.ZOrder = int.MinValue;
Background.CreateTexture(); Background.CreateTexture();
CameraView = new Rectangle( CameraView = new Rectangle(
@ -277,20 +280,29 @@ namespace DotSDL.Graphics {
Render.SetRenderTarget(_renderer, _texture); Render.SetRenderTarget(_renderer, _texture);
// Blit the background canvases to the target texture. // Sort all of the canvases, then draw them.
foreach(var canvas in Layers) { _drawList.Clear();
canvas.Clipping.Position = CameraView.Position; _drawList.AddRange(Layers.Where(l => l.Shown).ToArray());
canvas.Clipping.Size = CameraView.Size; _drawList.AddRange(Sprites.Where(s => s.Shown).ToArray());
canvas.UpdateTexture();
unsafe { foreach(var canvas in _drawList.OrderBy(layer => layer.ZOrder)) {
var canvasClippingRect = canvas.Clipping.SdlRect; switch(canvas) {
Render.RenderCopy(_renderer, canvas.Texture, new IntPtr(&canvasClippingRect), IntPtr.Zero); case Sprite sprite:
DrawSprite(sprite);
break;
default:
canvas.Clipping.Position = CameraView.Position;
canvas.Clipping.Size = CameraView.Size;
canvas.UpdateTexture();
unsafe {
var canvasClippingRect = canvas.Clipping.SdlRect;
Render.RenderCopy(_renderer, canvas.Texture, new IntPtr(&canvasClippingRect), IntPtr.Zero);
}
break;
} }
} }
// Plot sprites on top of the background layer.
if(Sprites.Count > 0) DrawSprites();
Render.SetRenderTarget(_renderer, IntPtr.Zero); Render.SetRenderTarget(_renderer, IntPtr.Zero);
Render.RenderCopy(_renderer, _texture, IntPtr.Zero, IntPtr.Zero); Render.RenderCopy(_renderer, _texture, IntPtr.Zero, IntPtr.Zero);
@ -343,61 +355,58 @@ namespace DotSDL.Graphics {
} }
/// <summary> /// <summary>
/// Plots the sprites stored in <see cref="Sprites"/> to the screen. Please note that this method is called by /// Plots a sprite to the screen. Please note that this method is called by DotSDL's drawing
/// DotSDL's drawing routines and does not need to be called manually. Additionally, this method will not be /// routines and does not need to be called manually. Additionally, this method will never be
/// called if there are no sprites defined. You usually do not need to override this method. /// called if there are no active sprites. You usually do not need to override this method.
/// </summary> /// </summary>
public virtual void DrawSprites() { public virtual void DrawSprite(Sprite sprite) {
Render.SetRenderTarget(_renderer, _texture); var srcRect = sprite.Clipping.SdlRect;
foreach(var sprite in Sprites.Where(e => e.Shown).OrderBy(e => e.ZOrder)) { var drawSize = sprite.DrawSize;
var srcRect = sprite.Clipping.SdlRect;
var drawSize = sprite.DrawSize; Rectangle dest;
Point rotationCenter;
Rectangle dest; if(sprite.CoordinateSystem == CoordinateSystem.ScreenSpace) {
Point rotationCenter; dest = new Rectangle(sprite.Position, drawSize);
if(sprite.CoordinateSystem == CoordinateSystem.ScreenSpace) { rotationCenter = sprite.RotationCenter;
dest = new Rectangle(sprite.Position, drawSize); } else {
rotationCenter = sprite.RotationCenter; // Create a set of world coordinates based on the position of the camera
} else { // and this sprite.
// Create a set of world coordinates based on the position of the camera var relPosition = new Point(sprite.Position - CameraView.Position);
// and this sprite. var screenPosition = new Point(
var relPosition = new Point(sprite.Position - CameraView.Position); (int)((float)relPosition.X / CameraView.Size.X * RenderWidth),
var screenPosition = new Point( (int)((float)relPosition.Y / CameraView.Size.Y * RenderHeight)
(int)((float)relPosition.X / CameraView.Size.X * RenderWidth), );
(int)((float)relPosition.Y / CameraView.Size.Y * RenderHeight) var scaleFactorX = (float)RenderWidth / CameraView.Size.X;
); var scaleFactorY = (float)RenderHeight / CameraView.Size.Y;
var scaleFactorX = (float)RenderWidth / CameraView.Size.X; var size = new Point(
var scaleFactorY = (float)RenderHeight / CameraView.Size.Y; (int)(drawSize.X * scaleFactorX),
var size = new Point( (int)(drawSize.Y * scaleFactorY)
(int)(drawSize.X * scaleFactorX), );
(int)(drawSize.Y * scaleFactorY)
); dest = new Rectangle(screenPosition, size);
rotationCenter = new Point(
dest = new Rectangle(screenPosition, size); (int)(sprite.RotationCenter.X * scaleFactorX),
rotationCenter = new Point( (int)(sprite.RotationCenter.Y * scaleFactorY)
(int)(sprite.RotationCenter.X * scaleFactorX), );
(int)(sprite.RotationCenter.Y * scaleFactorY) }
);
}
var destRect = dest.SdlRect; var destRect = dest.SdlRect;
var rotationCenterPoint = rotationCenter.SdlPoint; var rotationCenterPoint = rotationCenter.SdlPoint;
unsafe { unsafe {
var srcRectPtr = new IntPtr(&srcRect); var srcRectPtr = new IntPtr(&srcRect);
var destRectPtr = new IntPtr(&destRect); var destRectPtr = new IntPtr(&destRect);
var rotationCenterPtr = new IntPtr(&rotationCenterPoint); var rotationCenterPtr = new IntPtr(&rotationCenterPoint);
Render.RenderCopyEx( Render.RenderCopyEx(
renderer: _renderer, renderer: _renderer,
texture: sprite.Texture, texture: sprite.Texture,
srcRect: srcRectPtr, srcRect: srcRectPtr,
dstRect: destRectPtr, dstRect: destRectPtr,
angle: sprite.Rotation, angle: sprite.Rotation,
center: rotationCenterPtr, center: rotationCenterPtr,
flip: sprite.Flip flip: sprite.Flip
); );
}
} }
} }
@ -537,17 +546,13 @@ namespace DotSDL.Graphics {
/// <summary> /// <summary>
/// Displays the window and begins executing code that's associated with it. /// Displays the window and begins executing code that's associated with it.
/// </summary> /// </summary>
public void Start() { public void Start() => Start(0, 0);
Start(0, 0);
}
/// <summary> /// <summary>
/// Displays the window and begins executing code that's associated with it. /// Displays the window and begins executing code that's associated with it.
/// </summary> /// </summary>
/// <param name="updateRate">The desired number of video and game logic updates per second. 0 causes the display and game to be updated as quickly as possible.</param> /// <param name="updateRate">The desired number of video and game logic updates per second. 0 causes the display and game to be updated as quickly as possible.</param>
public void Start(float updateRate) { public void Start(float updateRate) => Start(updateRate, updateRate);
Start(updateRate, updateRate);
}
/// <summary> /// <summary>
/// Displays the window and begins executing code that's associated with it. /// Displays the window and begins executing code that's associated with it.

Loading…
Cancel
Save