Welcome Guest! To enable all features please Login or Register.

Notification

Icon
Error

Options
Go to last post Go to first unread
Offline Robert Walter  
#1 Posted : Saturday, September 3, 2011 5:43:35 PM(UTC)
Robert Walter

Joined: 8/24/2011(UTC)
Posts: 68

Thanks: 4 times
Hi,
i'm looking for function to draw a freeform curve pixel image on a canvas. I looked into the Mouse Tests and here especially, how to draw lines. I couldn't find a function to just draw a simple pixel, so I just used the line.draw() and something like (startpoint.Y+0.001f) as endpoint for the line, to get something which resembles kind of a pixel.
I want my project to be deployable on as many plattforms as possible, so I can't use WPF canvas, right?

Hope you understand, what I'm talking about :)
Thanks in advance!

Wanna join the discussion?! Login to your forum accountregister a new account. Or Connect via Facebook Twitter Google

Offline Benjamin  
#2 Posted : Saturday, September 3, 2011 10:19:02 PM(UTC)
Benjamin

Medals: Admin

Joined: 8/20/2011(UTC)
Posts: 1,421
Location: Hannover

Thanks: 18 times
Was thanked: 97 time(s) in 92 post(s)
Originally Posted by: University of Duisburg-Essen Go to Quoted Post
Hi,
i'm looking for function to draw a freeform curve pixel image on a canvas. I looked into the Mouse Tests and here especially, how to draw lines. I couldn't find a function to just draw a simple pixel, so I just used the line.draw() and something like (startpoint.Y+0.001f) as endpoint for the line, to get something which resembles kind of a pixel.
I want my project to be deployable on as many plattforms as possible, so I can't use WPF canvas, right?

Hope you understand, what I'm talking about :)
Thanks in advance!


WPF won't be very helpful as it ONLY works on Windows (not even Linux or MacOS and certainly not iOS/Android/WP7/etc.)

There are many ways to draw pixels:
- You can draw pixels directly to bitmaps (use the BitmapHelper class or do it directly with the System.Drawing.Bitmap class), then you can pass this to a texture and material for rendering. This is the easiest and slowest way, but good enough for example for the MiniMap in ArenaWars (which only needs to be generated once for each map).
- Another good and better optimized way is to draw lines or points (functionality can easily be added to Delta.Graphics.OpenTK) directly on the screen or into render to texture targets to keep the results from frame to frame.
- Post screen effects or other advanced rendering techniques can also be used to keep data around or draw shapes and stuff onto the scene or textures.

As long as your performance is good, stick with Line.Draw and just draw pixels this way :)
Offline Robert Walter  
#3 Posted : Thursday, September 8, 2011 11:39:58 AM(UTC)
Robert Walter

Joined: 8/24/2011(UTC)
Posts: 68

Thanks: 4 times
Thanks for your answer.
I draw pixels now with drawLine, when the left mouse button is pressed and save the points to a StackList, to draw the points every frame.
Code:
if (Input.Mouse.IsPressed(InputButton.MouseLeft))
				{
                    pointList.Push(Input.Mouse.Position);
				}

 for (int i = 0; i < pointList.Count; i++) 
                {
                    endpoint = new Point(pointList[i].X, pointList[i].Y + 0.001f);
                    Line.Draw(pointList[i], endpoint, Color.Red); 
                    
                }



Now I got the problem, that when I drag the mouse fast, not all pixels will be stored to the StackList. I get wide gaps between pixels. As I intend to do a simple drawing application, this isn't nice ;)
I will now have a look into System.Drawing, as you mentioned.
Offline Benjamin  
#4 Posted : Thursday, September 8, 2011 12:54:04 PM(UTC)
Benjamin

Medals: Admin

Joined: 8/20/2011(UTC)
Posts: 1,421
Location: Hannover

Thanks: 18 times
Was thanked: 97 time(s) in 92 post(s)
Well, since you already use lines, you pretty much solved that problem already. All you have to do is to draw between the points and not just the points themselves.

Code:

for (int i = 0; i < pointList.Count-1; i++) 
{
                    Line.Draw(pointList[i], pointList[i+1], Color.Red);                   
}


Thats it, looks even easier than your code :)
thanks 1 user thanked Benjamin for this useful post.
Robert Walter on 9/8/2011(UTC)
Offline Robert Walter  
#5 Posted : Thursday, September 8, 2011 1:01:39 PM(UTC)
Robert Walter

Joined: 8/24/2011(UTC)
Posts: 68

Thanks: 4 times
Thanks again. ThumpUp

Should have thought about that, before posting...Blushing
Offline Robert Walter  
#6 Posted : Saturday, September 10, 2011 10:38:36 AM(UTC)
Robert Walter

Joined: 8/24/2011(UTC)
Posts: 68

Thanks: 4 times
If anyone is interested. Here is the complete code, to draw an image in a predefined canvas area. You can draw different forms, everytime the mouse button is released. The drawing will be also be stored in a list of absolute coordinates:
Code:

            StackList<bool> conList = new StackList<bool>();
            StackList<Point> pointList = new StackList<Point>();
            StackList<Point> pixelImage = new StackList<Point>(); //stores the absolute pixel coordinates
            Rectangle drawingCanvas = new Rectangle(0.4f, 0.4f, 0.2f, 0.2f);

            Rectangle pixelCanvas = Screen.ToPixelSpace(drawingCanvas);

            bool pressed = false;

            Application.Start(delegate
			{
                //the drawing canvas area
                Rect.DrawOutline(drawingCanvas, Color.Yellow);

                //draw all points out of the pointlist
                for (int i = 0; i < pointList.Count-1; i++) 
                {
                    //draw only lines between points, which where drawn while left mouse button was pressed
                    //thus each time the mouse button is released and pressed again a new object is drawn
                    if ((conList[i] == true) && (conList[i+1] != false))
                    {
                        Line.Draw(pointList[i], pointList[i + 1], Color.Red);
                    }
                }
                

				if (Input.Mouse.IsPressed(InputButton.MouseLeft))
				{
                    //check if mouse is inside drawing canvas
                    if ((Input.Mouse.Position.X > 0.4f) && (Input.Mouse.Position.X < 0.6f) && (Input.Mouse.Position.Y > 0.4f) && (Input.Mouse.Position.Y < 0.6f))
                    {
                        //don't put points twice into the list
                        if (!pointList.Contains(Input.Mouse.Position))
                        {
                            conList.Push(true);
                            pointList.Push(Input.Mouse.Position);
                            Point point = Input.Mouse.Position;
                            pixelImage.Push(Screen.ToPixelSpace(point));
                        }
                    }
                    pressed = true;
				} 

                if (Input.Mouse.IsReleased(InputButton.MouseLeft) && pressed == true) 
                { 
                    //check if mouse is inside drawing canvas
                    if ((Input.Mouse.Position.X > 0.4f) && (Input.Mouse.Position.X < 0.6f) && (Input.Mouse.Position.Y > 0.4f) && (Input.Mouse.Position.Y < 0.6f))
                    {
                        
                        conList.Push(false);
                        pointList.Push(Input.Mouse.Position);
                        
                    }
                    pressed = false;
                }

Edited by user Saturday, September 10, 2011 10:39:16 AM(UTC)  | Reason: Not specified

Offline Robert Walter  
#7 Posted : Wednesday, September 14, 2011 4:22:53 PM(UTC)
Robert Walter

Joined: 8/24/2011(UTC)
Posts: 68

Thanks: 4 times
With my StackList pixelImage I thought I could easily build a bmp image, but I didn't found a solution so far. I can't use System.Drawing, because it conflicts with Delta Engine. Is it possible with Delta Engine, because I haven't found anything up to now. Thanks in advance! :)
Offline Benjamin  
#8 Posted : Wednesday, September 14, 2011 7:05:42 PM(UTC)
Benjamin

Medals: Admin

Joined: 8/20/2011(UTC)
Posts: 1,421
Location: Hannover

Thanks: 18 times
Was thanked: 97 time(s) in 92 post(s)
Not sure why you want to use System.Drawing (extra assemblies that might not work on all platforms and that are specific to Windows can cause problems, however System.Drawing is something we could map to our calls in the future, System.Windows.Forms is harder to support).

But if you have a type conflict in your code, just use the full type name in your code (e.g. Delta.Utilities.Datatypes.Point) or add a using line specifying which class you really want:

Code:

using Point = Delta.Utilities.Datatypes.Point;


What you probably want to do is to use the helper methods in Graphics and Texture to create Delta Engine images and textures you can use for rendering materials from pixel data (RGB or RGBA). Check out the Texture.Create methods!
Offline Robert Walter  
#9 Posted : Tuesday, November 15, 2011 6:31:01 PM(UTC)
Robert Walter

Joined: 8/24/2011(UTC)
Posts: 68

Thanks: 4 times
Ok, got all of the parts I need for my program running, but I need to have "bigger" pixels. Thus I would like to increase the size of pixels affected with each mouse drawing. But can't figure out how this could be done best. Maybe by drawing really small filled rectangles on each pixel, which is drawn? Any help would be appreciated. Thanks :)
Offline Benjamin  
#10 Posted : Tuesday, November 15, 2011 9:19:25 PM(UTC)
Benjamin

Medals: Admin

Joined: 8/20/2011(UTC)
Posts: 1,421
Location: Hannover

Thanks: 18 times
Was thanked: 97 time(s) in 92 post(s)
Yes, doing it via filled shapes (Rectangles, Circles) is the most flexible solution. If you just want a line with the thickness of 2 pixels just use the following code:

Code:

Line.Draw(start, end, color);
Line.Draw(start+pixel.Width, end, color);
Line.Draw(start, end+pixel.Height, color);


Pixel should be initialized somewhere else (outside of your for loop or as a class member, then update when resolution changes):
Code:

Size pixel = ScreenArea.ToQuadraticSpace(Size.One);

Offline Robert Walter  
#11 Posted : Wednesday, November 16, 2011 1:35:17 PM(UTC)
Robert Walter

Joined: 8/24/2011(UTC)
Posts: 68

Thanks: 4 times
Coolio. Thanks for the reply.
Where can I find the ScreenArea class? Blushing Or do you meant ScreenSpace.ToQuadraticSpace(Size.One) ?

Edited by user Wednesday, November 16, 2011 1:37:28 PM(UTC)  | Reason: Not specified

Offline Benjamin  
#12 Posted : Wednesday, November 16, 2011 1:40:50 PM(UTC)
Benjamin

Medals: Admin

Joined: 8/20/2011(UTC)
Posts: 1,421
Location: Hannover

Thanks: 18 times
Was thanked: 97 time(s) in 92 post(s)
Yes, Delta.Engine.ScreenSpace (it was called ScreenArea earlier ^^).

See Documentation.
Offline Robert Walter  
#13 Posted : Wednesday, November 16, 2011 6:08:17 PM(UTC)
Robert Walter

Joined: 8/24/2011(UTC)
Posts: 68

Thanks: 4 times
Damn, just stumbled over another problem with my implementation.
I need to get all drawn pixels. Therefor I'm using a StackList<Point> (points in pixelSpace), which I fill with points, each time the left mouse button is pressed over a drawing canvas. Next I convert the StackList<point> into a bool[,] array with a size of my drawing canvas in pixels. I set those array fields to true, where I have pixel in my StackList<point>. The problem is, that I get gaps. (For display reasons I'm using Line.Draw() between two pixels as mentioned above in this topic, to get a nice drawing)
Now I have thought about a new way to get this bool array. I want to go pixel per pixel through the drawing canvas and look where there a pixels drawn, like this:

Code:

Point pixel;
Point pixelQuadratic;
            for (int y = 0; y < pixelSizeOfCanvas.Y; y++)
            {
                for (int x = 0; x < pixelSizeOfCanvas.X; x++)
                {
                    pixel = new Point((float) x, (float) y);
                    pixelQuadratic = ScreenSpace.ToQuadraticSpace(point);
                    /* Here I want to test, if the actual pixel is set to a color or not */

                }
            }


Is there a way to get the color or another property of the actual pixel, which I can use to fill my bool array? Thanks in advance! :)
Offline Benjamin  
#14 Posted : Wednesday, November 16, 2011 8:42:24 PM(UTC)
Benjamin

Medals: Admin

Joined: 8/20/2011(UTC)
Posts: 1,421
Location: Hannover

Thanks: 18 times
Was thanked: 97 time(s) in 92 post(s)
Yes you could implement your own line algorithm like Bresenham, but a much easier solution is shown in the new SimpleGameExample in v0.9.1, which just interpolates the last mouse or touch positions (use more interpolations if you still have gaps, or interpolate more often for big distances between points):

Code:

				// Add few interpolated entries between this one and the last, this
				// will make the output look much more smooth :)
				if (lastPositions.Count >= NumberOfInterpolations)
				{
					// This way the output looks more smooth :)
					Point p1 = drawLocation;
					Point p2 = lastPositions[
						lastPositions.Count - NumberOfInterpolations];
					long t1 = Time.Milliseconds;
					long t2 = lastTimeMs[
						lastTimeMs.Count - NumberOfInterpolations];
					for (int num = 1; num < NumberOfInterpolations; num++)
					{
						float interpolation = num / (float)NumberOfInterpolations;
						lastPositions.Add(Point.Lerp(p1, p2, interpolation));
						lastTimeMs.Add(MathHelper.Lerp(t1, t2, interpolation));
						lastColors.Add(newColor);
					}
				}
				lastPositions.Add(drawLocation);
				lastTimeMs.Add(Time.Milliseconds);
				lastColors.Add(newColor);


For the full code check out v0.9.1, which is coming out shortly ^^ or ask again and I will attach it.
thanks 1 user thanked Benjamin for this useful post.
Robert Walter on 11/17/2011(UTC)
Offline Robert Walter  
#15 Posted : Thursday, November 17, 2011 1:05:56 PM(UTC)
Robert Walter

Joined: 8/24/2011(UTC)
Posts: 68

Thanks: 4 times
Thank you!

So if I get it right. You look into array lastPositions and interpolate between the drawLocation and the point found at the position size of lastPositions - NumberOfInterpolations in the for loop for the value given in NumberOfInterpolations. You save all interpolated points in array lastPositions. Right?
But I don't get the purpose behind the if clause. It is true, when the number of stored points in lastPositions is bigger than or equal to the NumberOfInterpolations. But it doesn't know which points are stored, so for example if you have 3 points in lastPositions, like (1/1), (1/8) and (1/12). NumberOfInterpolations is set to 2 and drawLocation to (2/5). Then I would get one new interpolated point between 2/5 and 1/8. The result would still be a one pixel gap between those two. So I increase the NumberOfInterpolations to 3. Now I will interpolate between lastPositions[0] and drawLocation, which would be (1/1) and (2/5) and get two interpolated points and add them to lastPositions. As a result I would still have a one pixel wide gap. Mhhh... Confused
I think I'm getting something totally wrong here, am I?
Would be nice if you could attach the whole sample, so that I can get a better insight of how this is working. Big thanks in advance and for the great support so far ThumpUp
Offline Benjamin  
#16 Posted : Thursday, November 17, 2011 1:12:23 PM(UTC)
Benjamin

Medals: Admin

Joined: 8/20/2011(UTC)
Posts: 1,421
Location: Hannover

Thanks: 18 times
Was thanked: 97 time(s) in 92 post(s)
Here is the full sample (it is a little bit more than you need and not the prettiest code ever, but it is short and does pretty much what you want).
You can also just download v0.9.1 (available in a few hours) and check out the SimpleGameExample project yourself:

I don't fully understand your question. If you still have gaps between points just increase the NumberOfInterpolations (e.g. to 10 or more for testing). You could also optimize it a bit if you know the distance to the last point and the size of each point, then you would only need extra interpolations if the distance is bigger than the size of each point (e.g. moved 0.8 over screen, point size is 0.1, then you need at least 8 interpolations to connect them, maybe 16 to make it look more like a line).

Code:

	/// <summary>
	/// Game class, which is the entry point for this game. Manages all the game
	/// logic and displays everything. More complex games do this differently.
	/// </summary>
	class Game : DynamicModule
	{
		#region Constants
		/// <summary>
		/// Update the trail 60 times per second.
		/// </summary>
		private const int NumberOfUpdatesPerSecond = 60;
		/// <summary>
		/// Keep the trail for 2 seconds.
		/// </summary>
		private const int TrailLengthInSeconds = 2;
		/// <summary>
		/// Interpolate the trail to make it look more smooth than the input
		/// allowes (which might jump great distances).
		/// </summary>
		private const int NumberOfInterpolations = 3;
		#endregion

		#region Variables
		/// <summary>
		/// Just load the DeltaEngine image or if that is not available the
		/// DeltaEngineLogo image, which is always available.
		/// </summary>
		private readonly Material2DColored gameObject =
			new Material2DColored("DeltaEngineLogo");
		/// <summary>
		/// Welcome text, which can be changed once a UIClick happened.
		/// </summary>
		private string welcomeText =
			"Press Space, GamePad, Click or Touch to see the hidden message";
		/// <summary>
		/// Start drawing in the middle, but allow moving around with cursors or
		/// any input device returning position change (mouse, touch, gamepad).
		/// </summary>
		private Point drawLocation = Point.Half;

		/// <summary>
		/// Last positions for the trail that is slowly fading out.
		/// </summary>
		readonly List<Point> lastPositions = new List<Point>();
		/// <summary>
		/// Last times (in milliseconds) for the trail to reconstruct the size
		/// and rotation values.
		/// </summary>
		readonly List<long> lastTimeMs = new List<long>();
		/// <summary>
		/// Last colors for the trail to make everything a bit more colorful.
		/// </summary>
		readonly List<Color> lastColors = new List<Color>();
		/// <summary>
		/// Current color used for drawing the trail.
		/// </summary>
		private Color currentColor = Color.Random;
		/// <summary>
		/// Next color we are fading to for the trail.
		/// </summary>
		private Color nextColor = Color.Random;
		#endregion

		#region Constructor
		/// <summary>
		/// Constructor, do additional initialization code here if needed.
		/// </summary>
		public Game()
			: base("Simple Game", typeof(Application))
		{
			// Note: Normally in a game you would define those commands via the
			// InputSettings.xml in the ContentManager, don't use the commands here!
			Input.Commands[Command.UIClick].Add(delegate
			{
				Application.BackgroundColor = Color.DarkBlue;
				welcomeText = "You made it! Yay. Now write some game code :)";
			});
			CommandDelegate moveDrawLocation = delegate(CommandTrigger command)
			{
				//Log.Info("Position=" + command.Position + ", from " + command.Button);
				drawLocation = command.Position;//.Movement / 10.0f;
			};
			Input.Commands[Command.CameraRotateLeft].Add(moveDrawLocation);
			Input.Commands[Command.CameraRotateRight].Add(moveDrawLocation);
			Input.Commands[Command.CameraRotateUp].Add(moveDrawLocation);
			Input.Commands[Command.CameraRotateDown].Add(moveDrawLocation);
			Input.Commands[Command.QuitTest].Add(delegate
			{
				Application.Quit();
			});
		}
		#endregion

		#region Run
		/// <summary>
		/// Run game loop, this is called every frame to do all game logic updating.
		/// </summary>
		public override void Run()
		{
			// Show FPS
			Font.Default.DrawTopLeft("FPS: " + Time.Fps);

			// Draw the trail and then the current object
			for (int num = 0; num < lastPositions.Count; num++)
			{
				DrawGameObject(lastPositions[num], lastTimeMs[num], lastColors[num],
					num / (float)lastPositions.Count);
			}
			DrawGameObject(drawLocation, Time.Milliseconds, Color.White, 1.0f);

			// Change color every second
			if (Time.EverySecond)
			{
				currentColor = nextColor;
				nextColor = Color.Random;
			}

			// Remember position for the trail 30 times per second.
			if (Time.CheckEvery(1.0f / NumberOfUpdatesPerSecond))
			{
				while (lastPositions.Count >
					NumberOfUpdatesPerSecond * TrailLengthInSeconds)
				{
					lastPositions.RemoveAt(0);
					lastTimeMs.RemoveAt(0);
					lastColors.RemoveAt(0);
				}
				float colorPerecentage = (Time.Milliseconds % 1000) / 1000.0f;
				Color newColor = Color.Lerp(currentColor, nextColor,
					colorPerecentage);
				// Add few interpolated entries between this one and the last, this
				// will make the output look much more smooth :)
				if (lastPositions.Count >= NumberOfInterpolations)
				{
					// This way the output looks more smooth :)
					Point p1 = drawLocation;
					Point p2 = lastPositions[
						lastPositions.Count - NumberOfInterpolations];
					long t1 = Time.Milliseconds;
					long t2 = lastTimeMs[
						lastTimeMs.Count - NumberOfInterpolations];
					for (int num = 1; num < NumberOfInterpolations; num++)
					{
						float interpolation = num / (float)NumberOfInterpolations;
						lastPositions.Add(Point.Lerp(p1, p2, interpolation));
						lastTimeMs.Add(MathHelper.Lerp(t1, t2, interpolation));
						lastColors.Add(newColor);
					}
				}
				lastPositions.Add(drawLocation);
				lastTimeMs.Add(Time.Milliseconds);
				lastColors.Add(newColor);
			}

			// And a simple text message
			Font.Default.DrawCentered(welcomeText, new Point(0.5f,
				ScreenSpace.DrawArea.Bottom - Font.Default.LineHeight / 2));

			// Note: put your game logic here, it will be executed each frame.
			// There is no difference between update code and render code as all
			// rendering will happen optimized at the end of the frame anyway!
		}

		/// <summary>
		/// Draw game object, also used for the trail.
		/// </summary>
		/// <param name="position">Current position</param>
		/// <param name="milliseconds">Time for this object or trail</param>
		/// <param name="color">Color for the trail</param>
		/// <param name="alpha">Alpha for drawing</param>
		private void DrawGameObject(Point position, long milliseconds, Color color,
			float alpha)
		{
			gameObject.BlendColor = new Color(color, alpha);
			gameObject.Draw(Rectangle.FromCenter(position, gameObject.Size + 0.5f *
				gameObject.Size * MathHelper.Sin(milliseconds / 20.0f)),
				milliseconds / 10.0f);
		}
		#endregion
	}

Edited by user Thursday, November 17, 2011 1:17:43 PM(UTC)  | Reason: Not specified

Rss Feed  Atom Feed
Users browsing this topic
Forum Jump  
You cannot post new topics in this forum.
You cannot reply to topics in this forum.
You cannot delete your posts in this forum.
You cannot edit your posts in this forum.
You cannot create polls in this forum.
You cannot vote in polls in this forum.

Powered by YAF.NET | YAF.NET © 2003-2023, Yet Another Forum.NET
This page was generated in 0.154 seconds.