I remember advocating AgateLib to you, but it's hard to get into and it wont work without a bit of OpenGL knowledge. So it is as good time as ever to remember some OpenGL :)
First step would be to download OpenTK. You may want to google for any OpenTK tutorials, but since I doubt their existence, we will just code away.
After unpacking OpenTK somewhere, lauch MonoDevelop, Ctrl+Shift+N, select empty project, add references to the OpenTK.dll and System.Drawing, add new empty class named "PointsExample" or something, and that's it.
Now let's get those points on the screen! Here is a complete code with commentaries.
public class PointsExample : GameWindow
// These are clipping planes, forget them for now.
private const int nearPlane = 1;
private const int farPlane = 11;
// Here we will store mouse position on click.
private List<Vector2> points = new List<Vector2>(32);
: base(800, 600, OpenTK.Graphics.GraphicsMode.Default, "The shortest distance between two points is under construction.")
// It's a bad karma to place complex logic in constructors,
// so we will perform initialization elsewhere.
protected override void OnLoad(EventArgs e)
// This method will be called on window load,
// looks like a good place for initialization.
// Lets enable VSync and remove distracting buzz of coolers.
// Actually, coolers are still buzzing, because VSync won't work in windowed mode.
OpenTK.Graphics.GraphicsContext.CurrentContext.VSync = true;
// Depth buffer isn't needed for simple 2D drawing,
// so we tell OpenGl to not update it.
// Disable polygon culling, it's not needed in 2D drawing.
// Points will be drawn with anti-aliasing.
GL.PointSize(24.0f); // Make points large and noticable.
// Points will have smooth edges.
// Grab a kvass and read: http://www.songho.ca/opengl/gl_transform.html
// It's important to understand matrices, or your attempts at drawing
// will be constantly thwarted by math.
// Lets setup a projection by switching to projection matrix stack,
// then multiply identity matrix and a transformation that produces a parallel projection.
// Now (0, 0) is the top left, X coord is going to the right
// and Y coord is going to the bottom, both coords map to the screen pixels.
GL.Ortho(0, Width, Height, 0, nearPlane, farPlane);
// Still confused?
// Selectively read this: http://www.falloutsoftware.com/tutorials/gl/gl0.htm
// and keep in mind that even though we're drawing 2d stuff, we're doing so in the 3d world.
// Also notice that the near clip plane is set at depth of 1, and far plane at the depth of 11.
// Everything closer than 1 and farther than 11 will be cut off.
// Now coord (31, 63) would mean 32-nd pixel to the right from left border
// and 64-th pixel downwards from top border of the screen.
Mouse.ButtonDown += OnMouseClick;
private void OnMouseClick(object sender, MouseButtonEventArgs e)
// User clicks — we add a point for drawing later.
// Thanks to orthographic projection mouse coords
// directly correspond to the world coords.
// Later you may want to read about Project/Unproject.
points.Add(new Vector2(e.X, e.Y));
protected override void OnUnload(EventArgs e)
// Not used in this example,
// but typically you will want to do a complete deinitialization here.
protected override void OnResize(EventArgs e)
// Update viewport when resizing window.
// Uncomment these lines to disable scaling on screen resize:
// GL.Ortho(0, Width, Height, 0, nearPlane, farPlane);
protected override void OnUpdateFrame(FrameEventArgs e)
// Typically your game logic will be updated in this update loop.
// We don't have any time-dependent progress logic yet, so it's empty.
protected override void OnRenderFrame(FrameEventArgs e)
GL.ClearColor(Color.CornflowerBlue); // It's almost like XNA :)
GL.Clear(ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit);
// Finally, it's time to draw the points in the draw loop.
// Remember the setup of the clipping planes?
// We will need to draw our geometry somewhere between the two clip planes
// so it will be visible.
// Start operations on model-view matrix stack...
// Pushing matrices is not really needed in this simple example,
// but typically you will use PushMatrix before drawing object
// whose transformations depend on previously computed matrix,
// and that's going to happen very often.
// Remember that negative Z axis is going "into the screen", so we move vertices away from camera.
GL.Translate(0.0f, 0.0f, -((nearPlane+farPlane) / 2f));
// Begin drawing points.
// Read about drawing primitives here:
GL.Color3(Color.Gold); // From now on all vertices will be golden.
foreach(var point in points)
GL.End(); // End drawing points.
GL.PopMatrix(); // We pushed, so now we need to pop previous matrix from the stack.
static void Main()
using (var game = new PointsExample())
And that's all for a simple task of drawing colored points. I hope that you've found it useful and that I didn't do anything wrong :)