I have been wracking my brain for the past day or so trying to figure this one out, so I thought maybe someone here would be able to see what I'm doing wrong. I'm trying to create a texture that, given a point, will create a circular gradient emanating from that point. I originally had this implemented in a shader, but when I couldn't get it to display properly I re-implemented it in software to make sure I had the logic right. Apparently I don't.
Knowing that Image.SetPixel is a very slow operation, I attempted to create a 2D Color array and pass that in directly instead.
public static class Program
{ private static readonly Color CornflowerBlue
= new Color
(100,
149,
237); private static readonly Vector2i WindowSize
= new Vector2i
(1280,
720); public static void Main
() { RenderWindow window
= new RenderWindow
(new VideoMode
((uint)WindowSize
.X,
(uint)WindowSize
.Y),
"SFML Window"); window
.Closed += (sender, eventArgs
) => window
.Close(); Color
[,
] sourceMap
= new Color
[WindowSize
.X, WindowSize
.Y]; Vector2f startPointInTexels
= new Vector2f
(0,
0); for(int y
= 0; y
< sourceMap
.GetLength(1); y
++) { for (int x
= 0; x
< sourceMap
.GetLength(0); x
++) { Vector2f currentPixelInTexels
= new Vector2f
(x
/ (float)WindowSize
.X, y
/ (float)WindowSize
.Y); float dist
= Distance
(currentPixelInTexels
.X, currentPixelInTexels
.Y, startPointInTexels
.X, startPointInTexels
.Y); dist
= Math
.Min(dist, 1
.0f
); sourceMap
[x, y
] = new Color
((byte)(dist
* byte.MaxValue),
(byte)(dist
* byte.MaxValue),
(byte)(dist
* byte.MaxValue),
255); } } Sprite sprite
= new Sprite
(new Texture
(new Image
(sourceMap
))); while (window
.IsOpen()) { window
.DispatchEvents(); window
.Clear(CornflowerBlue
); window
.Draw(sprite
); window
.Display(); } } private static float Distance
(float x1,
float y1,
float x2,
float y2
) { float x
= Math
.Abs(x2
- x1
); float y
= Math
.Abs(y2
- y1
); return (float)Math
.Sqrt(x
* x
+ y
* y
); }}
But this results in the attached image. From what I can tell, it looks like the underlying OpenGL texture is using an incorrect stride or format, but I couldn't find any way to change these through SFML.NET's API. Does anyone know what I'm missing or doing wrong here?
There is a bug in the Image(Color[,]) constructor. The problem stems from attempting to pass a 2D array of color structs as a C style pointer array. Looking around I found ways to pass 2D arrays of integers as a C style pointer array (read here (http://limbioliong.wordpress.com/2011/06/21/passing-multi-dimensional-managed-array-to-c-part-1/)). I'm still looking at a way of passing the color struct array, but for now just copy your color array directly into a byte array.
This code works and provides the expected result, but is slower due to the extra copy.
RenderWindow window
= new RenderWindow
(new VideoMode
((uint)WindowSize
.X,
(uint)WindowSize
.Y),
"SFML Window"); window
.Closed += (sender, eventArgs
) => window
.Close(); Color
[,
] sourceMap
= new Color
[WindowSize
.X, WindowSize
.Y]; Vector2f startPointInTexels
= new Vector2f
(0,
0); for (int y
= 0; y
< sourceMap
.GetLength(1); y
++) { for (int x
= 0; x
< sourceMap
.GetLength(0); x
++) { Vector2f currentPixelInTexels
= new Vector2f
(x
/ (float)WindowSize
.X, y
/ (float)WindowSize
.Y); float dist
= Distance
(currentPixelInTexels
.X, currentPixelInTexels
.Y, startPointInTexels
.X, startPointInTexels
.Y); dist
= Math
.Min(dist, 1
.0f
); sourceMap
[x, y
] = new Color
((byte)(dist
* byte.MaxValue),
(byte)(dist
* byte.MaxValue),
(byte)(dist
* byte.MaxValue),
255); } } byte[] pixelarray
= new byte[WindowSize
.X * WindowSize
.Y * 4]; int pos
= 0; for (int y
= 0; y
< sourceMap
.GetLength(1); y
++) { for (int x
= 0; x
< sourceMap
.GetLength(0); x
++) { pixelarray
[pos
] = sourceMap
[x, y
].R; pixelarray
[pos
+ 1] = sourceMap
[x, y
].B; pixelarray
[pos
+ 2] = sourceMap
[x, y
].G; pixelarray
[pos
+ 3] = sourceMap
[x, y
].A; pos
+= 4; } } Sprite sprite
= new Sprite
(new Texture
(new Image
((uint)WindowSize
.X,
(uint)WindowSize
.Y, pixelarray
))); while (window
.IsOpen()) { window
.DispatchEvents(); window
.Clear(CornflowerBlue
); window
.Draw(sprite
); window
.Display(); }