diff --git a/DotSDL/Graphics/Canvas.cs b/DotSDL/Graphics/Canvas.cs
index 2ca8627..18ce637 100644
--- a/DotSDL/Graphics/Canvas.cs
+++ b/DotSDL/Graphics/Canvas.cs
@@ -9,7 +9,11 @@ namespace DotSDL.Graphics {
///
public class Canvas {
private int _width, _height;
- private bool _hasTexture;
+
+ ///
+ /// true if this has an SDL texture associated with it, otherwise false.
+ ///
+ protected bool HasTexture { get; set; }
///
/// The SDL_Texture that this maintains.
@@ -22,6 +26,16 @@ namespace DotSDL.Graphics {
///
public Color[] Pixels;
+ ///
+ /// Gets an that points to what should be displayed on the window's background. This is
+ /// useful if you're maintaining your own ARGB framebuffer and don't plan to use DotSDL's
+ /// object. You usually do not need to override this method.
+ ///
+ /// If an invalid is generated by this method, your application may
+ /// crash with a segmentation fault. When in doubt, override instead!
+ /// An containing the contents of the window's background.
+ public Func GetCanvasPointer;
+
///
/// Gets or sets the width of the texture.
///
@@ -74,28 +88,45 @@ namespace DotSDL.Graphics {
Clipping = clipping;
+ GetCanvasPointer = () => {
+ unsafe {
+ fixed(void* pixelPtr = Pixels) {
+ return (IntPtr)pixelPtr;
+ }
+ }
+ };
+
Resize();
}
///
/// Creates a texture or recreates it if it already exists.
///
- internal void CreateTexture() {
+ internal virtual void CreateTexture() {
+ CreateTexture(Render.TextureAccess.Streaming);
+ }
+
+ ///
+ /// Creates a texture or recreates it if it already exists.
+ ///
+ /// The access mode for this texture.
+ internal void CreateTexture(Render.TextureAccess textureAccess) {
if(Renderer == IntPtr.Zero) return;
DestroyTexture();
- Texture = Render.CreateTexture(Renderer, SdlPixels.PixelFormatArgb8888, Render.TextureAccess.Streaming, Width, Height);
- _hasTexture = true;
+ Texture = Render.CreateTexture(Renderer, SdlPixels.PixelFormatArgb8888, textureAccess, Width, Height);
+ HasTexture = true;
+
}
///
/// Destroys the texture associated with this .
///
internal void DestroyTexture() {
- if(!_hasTexture) return;
+ if(!HasTexture) return;
Render.DestroyTexture(Texture);
- _hasTexture = false;
+ HasTexture = false;
}
///
@@ -124,8 +155,19 @@ namespace DotSDL.Graphics {
protected void Resize() {
Pixels = new Color[Width * Height];
- if(_hasTexture)
+ if(HasTexture)
CreateTexture();
}
+
+ ///
+ /// Updates the texture associated with this . This function must be called when the
+ /// array is changed.
+ ///
+ /// true if the texture was successfully updated, otherwise false. This will return false if this hasn't been added to the sprite list.
+ internal bool UpdateTexture() {
+ if(!HasTexture) return false;
+ Render.UpdateTexture(Texture, IntPtr.Zero, GetCanvasPointer(), Width * 4);
+ return true;
+ }
}
}
diff --git a/DotSDL/Graphics/SdlWindow.cs b/DotSDL/Graphics/SdlWindow.cs
index 0216bd8..79a1855 100644
--- a/DotSDL/Graphics/SdlWindow.cs
+++ b/DotSDL/Graphics/SdlWindow.cs
@@ -179,12 +179,10 @@ namespace DotSDL.Graphics {
Render.SetRenderTarget(_renderer, _texture);
// Blit the Canvas to the target texture.
+ Background.UpdateTexture();
unsafe {
var canvasClippingRect = Background.Clipping.SdlRect;
- var canvasClippingRectPtr = new IntPtr(&canvasClippingRect);
-
- Render.UpdateTexture(Background.Texture, IntPtr.Zero, GetCanvasPointer(), Background.Width * 4);
- Render.RenderCopy(_renderer, Background.Texture, canvasClippingRectPtr, IntPtr.Zero);
+ Render.RenderCopy(_renderer, Background.Texture, new IntPtr(&canvasClippingRect), IntPtr.Zero);
}
// Plot sprites on top of the background layer.
@@ -226,7 +224,8 @@ namespace DotSDL.Graphics {
/// DotSDL's drawing routines and does not need to be called manually. Additionally, this method will not be
/// called if there are no sprites defined. You usually do not need to override this method.
///
- public virtual unsafe void DrawSprites() {
+ public virtual void DrawSprites() {
+ Render.SetRenderTarget(_renderer, _texture);
foreach(var sprite in Sprites.Where(e => e.Shown).OrderBy(e => e.ZOrder)) {
SetScalingQuality(sprite.ScalingQuality);
@@ -237,32 +236,20 @@ namespace DotSDL.Graphics {
);
var destRect = new Rectangle(sprite.Position, drawSize).SdlRect;
- var srcRectPtr = new IntPtr(&srcRect);
- var destRectPtr = new IntPtr(&destRect);
-
- Render.RenderCopyEx(
- renderer: _renderer,
- texture: _texture,
- srcRect: srcRectPtr,
- dstRect: destRectPtr,
- angle: sprite.Rotation,
- center: sprite.Position.SdlPoint,
- flip: sprite.Flip
- );
- }
- }
-
- ///
- /// Gets an that points to what should be displayed on the window's background. This is
- /// useful if you're maintaining your own ARGB framebuffer and don't plan to use DotSDL's
- /// object. You usually do not need to override this method.
- ///
- /// If an invalid is generated by this method, your application may
- /// crash with a segmentation fault. When in doubt, override instead!
- /// An containing the contents of the window's background.
- public virtual unsafe IntPtr GetCanvasPointer() {
- fixed(void* pixelsPtr = Background.Pixels) {
- return (IntPtr)pixelsPtr;
+ unsafe {
+ var srcRectPtr = new IntPtr(&srcRect);
+ var destRectPtr = new IntPtr(&destRect);
+
+ Render.RenderCopyEx(
+ renderer: _renderer,
+ texture: sprite.Texture,
+ srcRect: srcRectPtr,
+ dstRect: destRectPtr,
+ angle: sprite.Rotation,
+ center: sprite.RotationCenter.SdlPoint,
+ flip: sprite.Flip
+ );
+ }
}
}
diff --git a/DotSDL/Graphics/Sprite.cs b/DotSDL/Graphics/Sprite.cs
index d232bee..678d331 100644
--- a/DotSDL/Graphics/Sprite.cs
+++ b/DotSDL/Graphics/Sprite.cs
@@ -1,4 +1,6 @@
-using System.Numerics;
+using DotSDL.Interop.Core;
+using SdlPixels = DotSDL.Interop.Core.Pixels;
+using System.Numerics;
namespace DotSDL.Graphics {
///
@@ -120,8 +122,24 @@ namespace DotSDL.Graphics {
ZOrder = zOrder;
Shown = false;
- RotationCenter.X = clipping.Size.X / 2;
- RotationCenter.Y = clipping.Size.Y / 2;
+ RotationCenter = new Point(clipping.Size.X / 2, clipping.Size.Y / 2);
+ }
+
+ ///
+ /// Creates a texture or recreates it if it already exists.
+ ///
+ internal override void CreateTexture() {
+ CreateTexture(Render.TextureAccess.Static);
+ }
+
+ ///
+ /// Updates the texture associated with this . This function must be called when the
+ /// array is changed after adding this sprite to the sprite list associated
+ /// with the application's .
+ ///
+ /// true if the texture was successfully updated, otherwise false. This will return false if this hasn't been added to the sprite list.
+ public new bool UpdateTexture() {
+ return base.UpdateTexture();
}
}
}
diff --git a/DotSDL/Graphics/SpriteList.cs b/DotSDL/Graphics/SpriteList.cs
index 80b73ed..55b7b04 100644
--- a/DotSDL/Graphics/SpriteList.cs
+++ b/DotSDL/Graphics/SpriteList.cs
@@ -83,12 +83,13 @@ namespace DotSDL.Graphics {
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
///
- /// Creates a texture for a sprite prior to adding it to the list.
+ /// Creates a texture for a prior to adding it to the list.
///
- ///
+ /// The that needs to be initialized.
private void InitializeSprite(Canvas sprite) {
- sprite.Texture = Render.CreateTexture(_renderer, Pixels.PixelFormatArgb8888, Render.TextureAccess.Static,
- sprite.Width, sprite.Height);
+ sprite.Renderer = _renderer;
+ sprite.CreateTexture();
+ sprite.UpdateTexture();
}
///
diff --git a/Samples/Sample.Sprites/Player.cs b/Samples/Sample.Sprites/Player.cs
index 212cc98..621eb31 100644
--- a/Samples/Sample.Sprites/Player.cs
+++ b/Samples/Sample.Sprites/Player.cs
@@ -2,14 +2,67 @@
namespace Sample.Sprites {
public class Player : Sprite {
+ private const int Radius = 15;
+ private const int Size = 32;
+
private Color _color;
private int _speed;
- public Player(Color color, int speed) : base(64, 64) {
+ public Player(Color color, int speed, int playerId) : base(Size, Size, playerId) {
_color = color;
_speed = speed;
Shown = true;
+
+ // Draw some really rough yet strangely lovable circles.
+ for(var x = Radius; x > 1; x--) {
+ var rX = x;
+ var rY = 0;
+ var err = 0;
+
+ while(rX >= rY) {
+ PlotMirroredPoints(rX, rY);
+ PlotMirroredPoints(rY, rX);
+
+ rY += 1;
+ if(err <= 0) {
+ err += 2 * rY + 1;
+ }
+
+ if(err > 0) {
+ rX -= 1;
+ err -= 2 * rX + 1;
+ }
+ }
+
+ // Increase the brightness as we move further inside.
+ var newR = (short)(_color.R * 1.1);
+ _color.R = (byte)(newR > 255 ? 255 : newR);
+
+ var newG = (short)(_color.G * 1.1);
+ _color.G = (byte)(newG > 255 ? 255 : newG);
+
+ var newB = (short)(_color.B * 1.1);
+ _color.B = (byte)(newB > 255 ? 255 : newB);
+ }
+
+ // Plot a little line so that we can show rotation.
+ for(var y = Radius; y >= 0; y--) {
+ Pixels[GetIndex(Radius, y)] = new Color { R = 64, G = 255, B = 64 };
+ }
+ }
+
+ public void Move(Point delta) {
+ // TODO: Support some basic vector arithmetic for points.
+ Position.X += delta.X * _speed;
+ Position.Y += delta.Y * _speed;
+ }
+
+ private void PlotMirroredPoints(int x, int y) {
+ Pixels[GetIndex(Radius + x, Radius + y)] = _color;
+ Pixels[GetIndex(Radius + x, Radius - y)] = _color;
+ Pixels[GetIndex(Radius - x, Radius + y)] = _color;
+ Pixels[GetIndex(Radius - x, Radius - y)] = _color;
}
}
}
diff --git a/Samples/Sample.Sprites/Window.cs b/Samples/Sample.Sprites/Window.cs
index 2218f3e..79c7719 100644
--- a/Samples/Sample.Sprites/Window.cs
+++ b/Samples/Sample.Sprites/Window.cs
@@ -5,6 +5,10 @@ using System;
namespace Sample.Sprites {
public class Window : SdlWindow {
+ //private int _camX = 0, _camY = 0, _deltaX = 2, _deltaY = 1;
+ private Player _player1, _player2;
+ private Point _player1Delta, _player2Delta;
+
public Window(int scale) : base("Sprites Test",
new Point { X = WindowPosUndefined, Y = WindowPosUndefined },
256 * scale, 196 * scale,
@@ -15,6 +19,7 @@ namespace Sample.Sprites {
Background.Height = Background.Width = 1024;
GenerateBackground();
+ GeneratePlayers();
}
private void GenerateBackground() {
@@ -34,10 +39,20 @@ namespace Sample.Sprites {
}
}
+ // Darken every other layer, because why not. :)
+ for(var y = 2; y < Background.Height; y += 2) {
+ for(var x = 0; x < Background.Width; x++) {
+ var pix = Background.Width * y + x;
+ Background.Pixels[pix].R = (byte)(Background.Pixels[pix].R * 0.8);
+ Background.Pixels[pix].G = (byte)(Background.Pixels[pix].G * 0.8);
+ Background.Pixels[pix].B = (byte)(Background.Pixels[pix].B * 0.8);
+ }
+ }
+
// Finally, draw a dashed border around the edge to show the edge boundaries.
// This routine assumes that the canvas is square.
const int lineSize = 7;
- const int margin = 1;
+ const int margin = 4;
var black = new Color { R = 0, G = 0, B = 0 };
var yellow = new Color { R = 255, G = 255, B = 0 };
@@ -60,18 +75,90 @@ namespace Sample.Sprites {
}
}
- protected override void OnDraw() {
+ private void GeneratePlayers() {
+ _player1 = new Player(new Color { R = 255, G = 64, B = 64 }, 2, 1);
+ _player2 = new Player(new Color { R = 64, G = 64, B = 255 }, 3, 2);
+
+ _player1.Position.X = 24;
+ _player1.Position.Y = 24;
+ _player1Delta = new Point();
+
+ _player2.Position.X = 96;
+ _player2.Position.Y = 24;
+ _player2Delta = new Point();
+
+ Sprites.Add(_player1);
+ Sprites.Add(_player2);
}
private void OnKeyPressed(object sender, KeyboardEvent e) {
- if(e.Keycode == Keycode.Escape)
- Stop();
+ switch(e.Keycode) {
+ case Keycode.Escape:
+ Stop();
+ break;
+ case Keycode.W:
+ _player1Delta.Y = -1;
+ break;
+ case Keycode.S:
+ _player1Delta.Y = 1;
+ break;
+ case Keycode.A:
+ _player1Delta.X = -1;
+ break;
+ case Keycode.D:
+ _player1Delta.X = 1;
+ break;
+ case Keycode.Up:
+ _player2Delta.Y = -1;
+ break;
+ case Keycode.Down:
+ _player2Delta.Y = 1;
+ break;
+ case Keycode.Left:
+ _player2Delta.X = -1;
+ break;
+ case Keycode.Right:
+ _player2Delta.X = 1;
+ break;
+ }
}
private void OnKeyReleased(object sender, KeyboardEvent e) {
+ switch(e.Keycode) {
+ case Keycode.W:
+ case Keycode.S:
+ _player1Delta.Y = 0;
+ break;
+ case Keycode.A:
+ case Keycode.D:
+ _player1Delta.X = 0;
+ break;
+ case Keycode.Up:
+ case Keycode.Down:
+ _player2Delta.Y = 0;
+ break;
+ case Keycode.Left:
+ case Keycode.Right:
+ _player2Delta.X = 0;
+ break;
+
+ }
}
protected override void OnUpdate() {
+ _player1.Move(_player1Delta);
+ _player2.Move(_player2Delta);
+
+ /*_camX += _deltaX;
+ _camY += _deltaY;
+
+ if(_camX + Background.Clipping.Size.X >= Background.Width || _camX <= 0)
+ _deltaX = -_deltaX;
+ if(_camY + Background.Clipping.Size.Y >= Background.Height || _camY <= 0)
+ _deltaY = -_deltaY;
+
+ Background.Clipping.Position.X = _camX;
+ Background.Clipping.Position.Y = _camY;*/
}
}
}