Browse Source

Pixel drawing works!

improved_timing
Ian Burgmyer 7 years ago
parent
commit
d07eeaaba9
  1. 2
      DotSDL/DotSDL.csproj
  2. 26
      DotSDL/Graphics/Color.cs
  3. 30
      DotSDL/Graphics/SdlWindow.cs
  4. 37
      DotSDL/Sdl/Render.cs
  5. 2
      Samples/Sample.BasicPixels/BasicPixels.cs
  6. 150
      Samples/Sample.BasicPixels/Window.cs

2
DotSDL/DotSDL.csproj

@ -9,7 +9,7 @@
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<AllowUnsafeBlocks>False</AllowUnsafeBlocks>
<AllowUnsafeBlocks>True</AllowUnsafeBlocks>
</PropertyGroup>
</Project>

26
DotSDL/Graphics/Color.cs

@ -0,0 +1,26 @@
using System.Runtime.InteropServices;
namespace DotSDL.Graphics {
[StructLayout(LayoutKind.Sequential)]
public struct Color {
/// <summary>
/// The blue channel.
/// </summary>
public byte B;
/// <summary>
/// The green channel.
/// </summary>
public byte G;
/// <summary>
/// The red channel.
/// </summary>
public byte R;
/// <summary>
/// The alpha channel.
/// </summary>
public byte A;
}
}

30
DotSDL/Graphics/SdlWindow.cs

@ -3,7 +3,7 @@ using DotSDL.Sdl;
namespace DotSDL.Graphics {
/// <summary>
/// Represents an SDL window. TODO: Support other pixel formats.
/// Represents an SDL window.
/// </summary>
public class SdlWindow {
private readonly IntPtr _window;
@ -12,6 +12,11 @@ namespace DotSDL.Graphics {
private bool _running;
public int Width { get; private set; }
public int Height { get; private set; }
private Color[] _pixels;
/// <summary>Indicates that the window manager should position the window.</summary>
public const int WindowPosUndefined = 0x1FFF0000;
public static int WindowPosUndefinedDisplay(uint x) {
@ -28,12 +33,21 @@ namespace DotSDL.Graphics {
_window = Video.CreateWindow(name, position.X, position.Y, width, height, Video.WindowFlags.Hidden);
_renderer = Render.CreateRenderer(_window, -1, Render.RendererFlags.Accelerated);
_texture = Render.CreateTexture(_renderer, Pixels.PixelFormatArgb8888, Render.TextureAccess.Streaming, width, height);
// TODO: Support other pixel formats.
_pixels = new Color[width * height];
Width = width;
Height = height;
}
private void BaseDraw() {
Render.LockTexture(_texture, IntPtr.Zero, out var pixels, out var pitch);
OnDraw(); // Call the overridden Draw function.
Render.UnlockTexture(_texture);
private unsafe void BaseDraw() {
OnDraw(ref _pixels); // Call the overridden Draw function.
fixed(void* pixelsPtr = _pixels) {
var ptr = (IntPtr)pixelsPtr;
Render.UpdateTexture(_texture, IntPtr.Zero, ptr, Width * 4);
}
Render.RenderCopy(_renderer, _texture, IntPtr.Zero, IntPtr.Zero);
Render.RenderPresent(_renderer);
@ -59,17 +73,17 @@ namespace DotSDL.Graphics {
/// <summary>
/// Fired every time the window is drawn to.
/// </summary>
public virtual void OnDraw() {}
protected virtual void OnDraw(ref Color[] pixels) {}
/// <summary>
/// Fired before the window is shown.
/// </summary>
public virtual void OnLoad() {}
protected virtual void OnLoad() {}
/// <summary>
/// Fired every time the application logic update runs.
/// </summary>
public virtual void OnUpdate() {}
protected virtual void OnUpdate() {}
/// <summary>
/// Displays the window and begins executing code that's associated with it.

37
DotSDL/Sdl/Render.cs

@ -62,20 +62,6 @@ namespace DotSDL.Sdl {
[DllImport(Meta.DllName, EntryPoint = "SDL_CreateTexture", CallingConvention = CallingConvention.Cdecl)]
internal static extern IntPtr CreateTexture(IntPtr renderer, uint format, TextureAccess access, int w, int h);
/// <summary>
/// Lock a portion of the texture for write-only pixel access.
/// </summary>
/// <param name="texture">The texture to lock for access, which was created with <see cref="TextureAccess.Streaming"/>.</param>
/// <param name="rect">The rectangle to lock for access. If the rect is NULL, the entire texture will be locked.</param>
/// <param name="pixels">This is filled in with an <see cref="IntPtr"/> to the locked pixels, appropriately offset
/// by the locked area.</param>
/// <param name="pitch">This is filled in with the pitch of the locked pixels.</param>
/// <returns>0 on success, or -1 if the texture is not valid or was not created with <see cref="TextureAccess.Streaming"/>.</returns>
[DllImport(Meta.DllName, EntryPoint = "SDL_LockTexture", CallingConvention = CallingConvention.Cdecl)]
internal static extern int LockTexture(IntPtr texture, Rect.SdlRect rect, out IntPtr pixels, out int pitch);
[DllImport(Meta.DllName, EntryPoint = "SDL_LockTexture", CallingConvention = CallingConvention.Cdecl)]
internal static extern int LockTexture(IntPtr texture, IntPtr rect, out IntPtr pixels, out int pitch);
/// <summary>
/// Clear the current rendering target with the drawing color.
///
@ -107,10 +93,25 @@ namespace DotSDL.Sdl {
internal static extern void RenderPresent(IntPtr renderer);
/// <summary>
/// Unlock a texture, uploading the changes to video memory, if needed.
/// Update the given texture rectangle with new pixel data.
/// </summary>
/// <param name="texture">The texture to update.</param>
/// <param name="rect">A rectangle of pixels to update, or NULL to update the entire texture.</param>
/// <param name="pixels">The raw pixel data.</param>
/// <param name="pitch">The number of bytes in a row of pixel data, including padding between lines.</param>
/// <returns>0 on success, or -1 if the texture is not valid.</returns>
[DllImport(Meta.DllName, EntryPoint = "SDL_UpdateTexture", CallingConvention = CallingConvention.Cdecl)]
internal static extern int UpdateTexture(IntPtr texture, IntPtr rect, IntPtr pixels, int pitch);
/// <summary>
/// Update the given texture rectangle with new pixel data.
/// </summary>
/// <param name="texture">The texture to unlock.</param>
[DllImport(Meta.DllName, EntryPoint = "SDL_UnlockTexture", CallingConvention = CallingConvention.Cdecl)]
internal static extern void UnlockTexture(IntPtr texture);
/// <param name="texture">The texture to update.</param>
/// <param name="rect">A rectangle of pixels to update, or NULL to update the entire texture.</param>
/// <param name="pixels">The raw pixel data.</param>
/// <param name="pitch">The number of bytes in a row of pixel data, including padding between lines.</param>
/// <returns>0 on success, or -1 if the texture is not valid.</returns>
[DllImport(Meta.DllName, EntryPoint = "SDL_UpdateTexture", CallingConvention = CallingConvention.Cdecl)]
internal static extern int UpdateTexture(IntPtr texture, Rect.SdlRect rect, IntPtr pixels, int pitch);
}
}

2
Samples/Sample.BasicPixels/BasicPixels.cs

@ -1,7 +1,7 @@
namespace DotSDL.Sample.BasicPixels {
internal class BasicPixels {
private static void Main(string[] args) {
var window = new Window(512, 512);
var window = new Window(512, 256);
window.Start();
}
}

150
Samples/Sample.BasicPixels/Window.cs

@ -1,11 +1,157 @@
using DotSDL.Graphics;
using System;
namespace DotSDL.Sample.BasicPixels {
internal class Window : SdlWindow {
public Window(int width, int height) : base("Basic Pixels", new Point { X = WindowPosUndefined, Y = WindowPosUndefined }, width, height) {}
public override void OnDraw() {
private struct Line {
public Point Start;
public Point End;
}
private void DrawBackground(ref Color[] pixels) {
byte d = 0;
var dec = false;
for(var i = 0; i < pixels.Length; i++) {
pixels[i].A = 255;
pixels[i].R = 0;
pixels[i].G = 0;
pixels[i].B = 0;
switch(i % 12 / 3) {
case 0:
pixels[i].R = (byte)(d / 2);
break;
case 1:
pixels[i].G = (byte)(d / 2);
break;
case 2:
pixels[i].B = (byte)(d / 2);
break;
}
if(dec) {
if(d == 0)
dec = false;
else
d--;
} else {
if(d == 255)
dec = true;
else
d++;
}
}
}
private void DrawLine(ref Color[] pixels, Color color, Line line) {
var dx = line.End.X - line.Start.X;
var dy = line.End.Y - line.Start.Y;
if(Math.Abs(dx) > Math.Abs(dy)) {
if(line.End.X > line.Start.X) {
for(var x = line.Start.X; x < line.End.X; x++) {
var y = line.Start.Y + dy * (x - line.Start.X) / dx;
pixels[GetPosition(x, y)] = color;
}
} else {
for(var x = line.Start.X; x > line.End.X; x--) {
var y = line.Start.Y + dy * (x - line.Start.X) / dx;
pixels[GetPosition(x, y)] = color;
}
}
} else {
if(line.End.Y > line.Start.Y) {
for(var y = line.Start.Y; y < line.End.Y; y++) {
var x = line.Start.X + dx * (y - line.Start.Y) / dy;
pixels[GetPosition(x, y)] = color;
}
} else {
for(var y = line.Start.Y; y > line.End.Y; y--) {
var x = line.Start.X + dx * (y - line.Start.Y) / dy;
pixels[GetPosition(x, y)] = color;
}
}
}
}
private void DrawSequence(ref Color[] pixels, Color color, params Line[] lines) {
foreach(var line in lines) {
DrawLine(ref pixels, color, line);
}
}
private int GetPosition(int x, int y) {
return (Width * y) + x;
}
protected override void OnDraw(ref Color[] pixels) {
const byte min = 128, max = 255;
const int offsetX = 96, offsetY = 80;
DrawBackground(ref pixels);
// D
DrawSequence(ref pixels, RandomColor(min, max),
new Line { Start = new Point { X = offsetX, Y = offsetY + 96 }, End = new Point { X = offsetX, Y = offsetY } },
new Line { Start = new Point { X = offsetX, Y = offsetY }, End = new Point { X = offsetX + 32, Y = offsetY } },
new Line { Start = new Point { X = offsetX + 32, Y = offsetY }, End = new Point { X = offsetX + 48, Y = offsetY + 16 } },
new Line { Start = new Point { X = offsetX + 48, Y = offsetY + 16 }, End = new Point { X = offsetX + 48, Y = offsetY + 80 } },
new Line { Start = new Point { X = offsetX + 48, Y = offsetY + 80 }, End = new Point { X = offsetX + 32, Y = offsetY + 96 } },
new Line { Start = new Point { X = offsetX + 32, Y = offsetY + 96 }, End = new Point { X = offsetX, Y = offsetY + 96 } }
);
// o
DrawSequence(ref pixels, RandomColor(min, max),
new Line { Start = new Point { X = offsetX + 64, Y = offsetY + 88}, End = new Point { X = offsetX + 64, Y = offsetY + 56 } },
new Line { Start = new Point { X = offsetX + 64, Y = offsetY + 56}, End = new Point { X = offsetX + 72, Y = offsetY + 48 } },
new Line { Start = new Point { X = offsetX + 72, Y = offsetY + 48}, End = new Point { X = offsetX + 80, Y = offsetY + 48 } },
new Line { Start = new Point { X = offsetX + 80, Y = offsetY + 48}, End = new Point { X = offsetX + 88, Y = offsetY + 56 } },
new Line { Start = new Point { X = offsetX + 88, Y = offsetY + 56}, End = new Point { X = offsetX + 88, Y = offsetY + 88 } },
new Line { Start = new Point { X = offsetX + 88, Y = offsetY + 88}, End = new Point { X = offsetX + 80, Y = offsetY + 96 } },
new Line { Start = new Point { X = offsetX + 80, Y = offsetY + 96}, End = new Point { X = offsetX + 72, Y = offsetY + 96 } },
new Line { Start = new Point { X = offsetX + 72, Y = offsetY + 96}, End = new Point { X = offsetX + 64, Y = offsetY + 88 } }
);
// t
DrawSequence(ref pixels, RandomColor(min, max),
new Line { Start = new Point { X = offsetX + 104 + 12, Y = offsetY + 24}, End = new Point { X = offsetX + 104 + 12, Y = offsetY + 96 } },
new Line { Start = new Point { X = offsetX + 104, Y = offsetY + 48}, End = new Point { X = offsetX + 104 + 24, Y = offsetY + 48 } }
);
// S
DrawSequence(ref pixels, RandomColor(min, max),
new Line { Start = new Point { X = offsetX + 144 + 48, Y = offsetY }, End = new Point { X = offsetX + 144, Y = offsetY } },
new Line { Start = new Point { X = offsetX + 144, Y = offsetY }, End = new Point { X = offsetX + 144, Y = offsetY + 48 } },
new Line { Start = new Point { X = offsetX + 144, Y = offsetY + 48 }, End = new Point { X = offsetX + 144 + 48 , Y = offsetY + 48 } },
new Line { Start = new Point { X = offsetX + 144 + 48, Y = offsetY + 48 }, End = new Point { X = offsetX + 144 + 48 , Y = offsetY + 96 } },
new Line { Start = new Point { X = offsetX + 144 + 48, Y = offsetY + 96 }, End = new Point { X = offsetX + 144, Y = offsetY + 96 } }
);
// D
DrawSequence(ref pixels, RandomColor(min, max),
new Line { Start = new Point { X = offsetX + 208, Y = offsetY + 96 }, End = new Point { X = offsetX + 208, Y = offsetY } },
new Line { Start = new Point { X = offsetX + 208, Y = offsetY }, End = new Point { X = offsetX + 208 + 32, Y = offsetY } },
new Line { Start = new Point { X = offsetX + 208 + 32, Y = offsetY }, End = new Point { X = offsetX + 208 + 48, Y = offsetY + 16 } },
new Line { Start = new Point { X = offsetX + 208 + 48, Y = offsetY + 16 }, End = new Point { X = offsetX + 208 + 48, Y = offsetY + 80 } },
new Line { Start = new Point { X = offsetX + 208 + 48, Y = offsetY + 80 }, End = new Point { X = offsetX + 208 + 32, Y = offsetY + 96 } },
new Line { Start = new Point { X = offsetX + 208 + 32, Y = offsetY + 96 }, End = new Point { X = offsetX + 208, Y = offsetY + 96 } }
);
// L
DrawSequence(ref pixels, RandomColor(min, max),
new Line { Start = new Point { X = offsetX + 272, Y = offsetY }, End = new Point { X = offsetX + 272, Y = offsetY + 96} },
new Line { Start = new Point { X = offsetX + 272, Y = offsetY + 96 }, End = new Point { X = offsetX + 272 + 48, Y = offsetY + 96} }
);
}
private Color RandomColor(byte min, byte max) {
var color = new Color();
var rng = new Random();
color.A = 255;
color.R = (byte)rng.Next(min, max);
color.G = (byte)rng.Next(min, max);
color.B = (byte)rng.Next(min, max);
return color;
}
}
}

Loading…
Cancel
Save