Browse Source

Added Canvas color/alpha mod support.

* Canvases can now be color shifted and made translucent.
    * Added missing XMLDocs.
    * Added a function to restore the GetCanvasPointer function pointer
      to its default value if the application decides to hand control of
      the pixel array back to the Canvas.
improved_timing
Ian Burgmyer 5 years ago
parent
commit
7bcd445ea7
  1. 77
      DotSDL/Graphics/Canvas.cs
  2. 20
      DotSDL/Interop/Core/Render.cs
  3. 39
      Samples/Sample.Sprites/Player.cs
  4. 2
      Samples/Sample.Sprites/Window.cs

77
DotSDL/Graphics/Canvas.cs

@ -9,6 +9,8 @@ namespace DotSDL.Graphics {
/// </summary>
public class Canvas {
private int _width, _height;
private Color _colorMod = new Color { R = 255, G = 255, B = 255, A = 255 };
private byte _opacity = 255;
/// <summary>
/// <c>true</c> if this <see cref="Canvas"/> has an SDL texture associated with it, otherwise <c>false</c>.
@ -78,6 +80,9 @@ namespace DotSDL.Graphics {
}
}
/// <summary>
/// Sets the blending mode that should be used for this <see cref="Canvas"/>.
/// </summary>
public BlendMode BlendMode {
get => BlendModeValue;
set {
@ -88,6 +93,52 @@ namespace DotSDL.Graphics {
}
}
/// <summary>
/// Gets or sets the color modulation that should be used for this <see cref="Canvas"/>.
/// </summary>
/// <remarks>
/// <para>Each pixel of this <see cref="Canvas"/> will be multiplied by the
/// <see cref="Color"/> set here. This can be used to change the color of any
/// individual element without having to manually draw multiplie textures with
/// different palettes.</para>
///
/// <para>Alpha values will not affect the object in any way. In order to adjust
/// the object's translucency, use the <see cref="Opacity"/> property instead.</para>
///
/// <para>Please note that setting this will impact the entire object. No options
/// for masking are provided.</para>
/// </remarks>
public Color ColorMod {
get => _colorMod;
set {
_colorMod = value;
if(HasTexture)
Render.SetTextureColorMod(Texture, _colorMod.R, _colorMod.G, _colorMod.B);
}
}
/// <summary>
/// Gets or sets the opacity of this <see cref="Canvas"/>.
/// </summary>
/// <remarks>
/// <para>The alpha value of each pixel of this <see cref="Canvas"/> will be
/// multiplied by the value set here. This can be used to fade an entire object
/// in and out.</para>
///
/// <para>Please note that this setting will impact the entire object. No options
/// for masking are provided.</para>
/// </remarks>
public byte Opacity {
get => _opacity;
set {
_opacity = value;
if(HasTexture)
Render.SetTextureAlphaMod(Texture, _opacity);
}
}
/// <summary>
/// Determines the method that will be used to scale this sprite when it is plotted to the
/// screen.
@ -128,14 +179,7 @@ namespace DotSDL.Graphics {
Clipping = clipping;
GetCanvasPointer = () => {
unsafe {
fixed(void* pixelPtr = Pixels) {
return (IntPtr)pixelPtr;
}
}
};
ResetGetCanvasPointer();
Resize();
}
@ -158,7 +202,9 @@ namespace DotSDL.Graphics {
Texture = Render.CreateTexture(Renderer, SdlPixels.PixelFormatArgb8888, textureAccess, Width, Height);
HasTexture = true;
Render.SetTextureAlphaMod(Texture, _opacity);
Render.SetTextureBlendMode(Texture, BlendModeValue);
Render.SetTextureColorMod(Texture, _colorMod.R, _colorMod.G, _colorMod.B);
}
/// <summary>
@ -190,6 +236,21 @@ namespace DotSDL.Graphics {
return (Width * point.Y) + point.X;
}
/// <summary>
/// Restores the the <see cref="GetCanvasPointer"/> function pointer back to its normal
/// value. This should be called if the application wishes to give control of the pixel
/// array back to this <see cref="Canvas"/> after previously handling it.
/// </summary>
public void ResetGetCanvasPointer() {
GetCanvasPointer = () => {
unsafe {
fixed(void* pixelPtr = Pixels) {
return (IntPtr)pixelPtr;
}
}
};
}
/// <summary>
/// Resizes the <see cref="Canvas"/>. Please note that this will also clear the canvas of
/// its existing contents.

20
DotSDL/Interop/Core/Render.cs

@ -146,6 +146,26 @@ namespace DotSDL.Interop.Core {
[DllImport(Meta.CoreLib, EntryPoint = "SDL_RenderPresent", CallingConvention = CallingConvention.Cdecl)]
internal static extern void RenderPresent(IntPtr renderer);
/// <summary>
/// Sets an additional alpha value that will be multiplied into render copy operations.
/// </summary>
/// <param name="texture">The texture to update.</param>
/// <param name="alpha">The source alpha value multiplied into copy operations.</param>
/// <returns>0 on success or a negative error code on failure.</returns>
[DllImport(Meta.CoreLib, EntryPoint = "SDL_SetTextureAlphaMod", CallingConvention = CallingConvention.Cdecl)]
internal static extern int SetTextureAlphaMod(IntPtr texture, byte alpha);
/// <summary>
/// Modulates the color of a texture when it is used in a render copy operation.
/// </summary>
/// <param name="texture">The texture to update.</param>
/// <param name="r">The red color value multiplied into copy operations.</param>
/// <param name="g">The green color value multiplied into copy operations.</param>
/// <param name="b">The blue color value multiplied into copy operations.</param>
/// <returns>0 on success or a negative error code on failure.</returns>
[DllImport(Meta.CoreLib, EntryPoint = "SDL_SetTextureColorMod", CallingConvention = CallingConvention.Cdecl)]
internal static extern int SetTextureColorMod(IntPtr texture, byte r, byte g, byte b);
/// <summary>
/// Sets a texture as the current rendering target.
/// </summary>

39
Samples/Sample.Sprites/Player.cs

@ -5,26 +5,28 @@ namespace Sample.Sprites {
private const int Radius = 15;
private const int Size = 32;
private Color _color;
private int _speed;
public Player(Color color, int speed, int playerId) : base(Size, Size, playerId) {
const int baseAlpha = 128;
const byte baseAlpha = 128;
_color = color;
ColorMod = color;
_speed = speed;
Shown = true;
var gray = (byte)192;
// Draw some really rough yet strangely lovable circles.
for(var x = Radius; x > 1; x--) {
var rX = x;
var rY = 0;
var err = 0;
var alpha = (byte)(baseAlpha + ((float)Radius - x + 1) / Radius * (255 - baseAlpha));
while(rX >= rY) {
PlotMirroredPoints(rX, rY);
PlotMirroredPoints(rY, rX);
PlotMirroredPoints(rX, rY, gray, alpha);
PlotMirroredPoints(rY, rX, gray, alpha);
rY += 1;
if(err <= 0) {
@ -37,22 +39,14 @@ namespace Sample.Sprites {
}
}
// Increase the brightness and alpha as we move further inside.
_color.A = (byte)(baseAlpha + ((float)Radius - x + 1) / Radius * (255 - baseAlpha));
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);
// Increase the brightness as we move further inside.
var newGray = (short)(gray * 1.025);
gray = (byte)(newGray > 255 ? 255 : newGray);
}
// 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, A = 255 };
Pixels[GetIndex(Radius, y)] = new Color { R = 64, G = 64, B = 64, A = 128 };
}
}
@ -62,11 +56,12 @@ namespace Sample.Sprites {
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;
private void PlotMirroredPoints(int x, int y, byte gray, byte alpha) {
var color = new Color { R = gray, G = gray, B = gray, A = alpha };
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;
}
}
}

2
Samples/Sample.Sprites/Window.cs

@ -81,10 +81,12 @@ namespace Sample.Sprites {
_player1.Position.X = 24;
_player1.Position.Y = 24;
_player1.Opacity = 128;
_player1Delta = new Point();
_player2.Position.X = 96;
_player2.Position.Y = 24;
_player2.Opacity = 196;
_player2Delta = new Point();
_player1.Scale.X = 1.5f;

Loading…
Cancel
Save