Click here to Skip to main content
15,879,474 members
Articles / Multimedia / OpenGL

2D Drawing with an OpenGL Control

Rate me:
Please Sign up or sign in to vote.
4.87/5 (30 votes)
8 Feb 2010CPOL2 min read 209.8K   7.7K   130  
An article explaning how to create a user control for 2D shape drawing with OpenGL
#pragma once

#include <windows.h>
#include <GL/gl.h>
#include <GL/glu.h>

#include "Point3D.h"
#include "Camera.h"

using namespace System;
using namespace System::Drawing;
using namespace System::ComponentModel;
using namespace System::Windows::Forms;

namespace GLView 
{
	// Forward class declarations
	ref class GLGraphics3D;
	ref class Camera;

	/// <summary>
	/// Represents a 2D drawing canvas utilizing OpenGL.
	/// </summary>
	[ToolboxBitmap(GLView::GLCanvas3D::typeid)]
    [DefaultEvent("Render")]
	public ref class GLCanvas3D : public System::Windows::Forms::UserControl
	{
	// Constructor/destructor
	public:
		GLCanvas3D();

	protected:
		~GLCanvas3D();

	public:
		ref class GLGraphics3D;

	// Member variables
	private:
		HDC mhDC;
		HGLRC mhGLRC;
		bool mIsAccelerated;
		Camera ^ mCamera;
	    bool mPanning;
		PointF mLastMouse;
		Point3D mOrigin;
		float mSize;
		bool mAntiAlias;
		GLuint base, rasterbase;
		System::Drawing::Color mFloorColor;
		System::Drawing::Color mGridColor;
		bool mLighting;

	public:
		/// <summary>
		/// Determines whether hardware acceleration is enabled.
		/// </summary>
		[Category("Behavior"), Browsable(false), Description("Determines whether hardware acceleration is enabled.")] 
		property bool IsAccelerated
		{
			virtual bool get(void) { return mIsAccelerated; }
		}
		/// <summary>
		/// Determines whether zooming and panning with the mouse is allowed.
		/// </summary>
		[Category("Behavior"), Browsable(true), DefaultValue(true), Description("Determines whether zooming and panning with the mouse is allowed.")] 
		property bool AllowZoomAndPan;
		/// <summary>
		/// The cursor that appears when the pointer moves over the control.
		/// </summary>
		[Category("Appearance"), Browsable(true), DefaultValue(Windows::Forms::Cursor::typeid, "Cross"), Description("The cursor that appears when the pointer moves over the control.")]
        property Windows::Forms::Cursor ^ Cursor
		{
			virtual Windows::Forms::Cursor ^ get(void) override { return Control::Cursor; }
			virtual void set(Windows::Forms::Cursor ^ value) override { Control::Cursor = value; }
		}
		/// <summary>
		/// Determines whether the floor is drawn.
		/// </summary>
		[Category("Appearance"), Browsable(true), DefaultValue(true), Description("Determines whether the floor is drawn.")] 
		property bool DrawFloor;
		/// <summary>
		/// Determines whether the axis is drawn.
		/// </summary>
		[Category("Appearance"), Browsable(true), DefaultValue(true), Description("Determines whether the axis is drawn.")] 
		property bool ShowAxis;
		/// <summary>
		/// Gets or sets the color of floor.
		/// </summary>
		[Category("Appearance"), Browsable(true), DefaultValue(System::Drawing::Color::typeid, "Beige"), Description("Gets or sets the color of floor.")]
		property Drawing::Color FloorColor
		{
			virtual Drawing::Color get(void) { return mFloorColor; }
			virtual void set(Drawing::Color value) { mFloorColor = value; Invalidate(); }
		}
		/// <summary>
		/// Gets or sets the color of grid lines.
		/// </summary>
		[Category("Appearance"), Browsable(true), DefaultValue(System::Drawing::Color::typeid, "Bisque"), Description("Gets or sets the color of grid lines.")]
		property Drawing::Color GridColor
		{
			virtual Drawing::Color get(void) { return mGridColor; }
			virtual void set(Drawing::Color value) { mGridColor = value; Invalidate(); }
		}
		/// <summary>
		/// Gets or sets the background color of the control.
		/// </summary>
		[Category("Appearance"), Browsable(true), DefaultValue(System::Drawing::Color::typeid, "White"), Description("Gets or sets the background color of the control.")]
		property Drawing::Color BackColor
		{
			virtual Drawing::Color get(void) override { return Control::BackColor; }
			virtual void set(Drawing::Color value) override { Control::BackColor = value; Invalidate(); }
		}
		/// <summary>
		/// Determines whether lines are anti-aliased.
		/// </summary>
		[Category("Appearance"), Browsable(true), DefaultValue(true), Description("Determines whether lines are anti-aliased.")]
		property bool AntiAlias
		{
			virtual bool get(void) { return mAntiAlias; }
			virtual void set(bool value) 
			{ 
				if (value)
					glEnable(GL_LINE_SMOOTH);
				else
					glDisable(GL_LINE_SMOOTH);
				mAntiAlias = value; 
				Invalidate(); 
			}
		}
		/// <summary>
		/// Determines whether simple lighting model is active.
		/// </summary>
		[Category("Appearance"), Browsable(true), DefaultValue(true), Description("Determines whether simple lighting model is active.")]
		property bool Lighting
		{
			virtual bool get(void) { return mLighting; }
			virtual void set(bool value) 
			{ 
				if (value)
				{
					glEnable(GL_LIGHTING);
					glEnable(GL_LIGHT0);
					glEnable(GL_COLOR_MATERIAL);
					GLfloat pos[] = { 1, 1, 1 };
					GLfloat amb[] = { 0, 0, 0, 1 };
					GLfloat dif[] = { 1, 1, 1, 1 };
					glLightfv(GL_LIGHT0, GL_POSITION, pos);
					glLightfv(GL_LIGHT0, GL_AMBIENT, amb);
					glLightfv(GL_LIGHT0, GL_DIFFUSE, dif);
					glLightfv(GL_LIGHT0, GL_SPECULAR, dif);
					glColorMaterial(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE);
					glMaterialfv(GL_FRONT_AND_BACK, GL_EMISSION, amb);
					GLfloat mspec[] = { 0, 0, 0, 1 };
					glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, mspec);
				}
				else
				{
					glDisable(GL_LIGHTING);
					glDisable(GL_LIGHT0);
					glDisable(GL_COLOR_MATERIAL);
				}
				mLighting = value; 
				Invalidate(); 
			}
		}
		/// <summary>
		/// Returns the display list used to draw vector text.
		/// </summary>
		[Category("Appearance"), Browsable(false), Description("Returns the display list used to draw vector text.")] 
		property GLuint VectorListBase
		{
			virtual GLuint get(void) { return base; }
		}
		/// <summary>
		/// Returns the display list used to draw raster text.
		/// </summary>
		[Category("Appearance"), Browsable(false), Description("Returns the display list used to draw raster text.")] 
		property GLuint RasterListBase
		{
			virtual GLuint get(void) { return rasterbase; }
		}
		/// <summary>
		/// Gets or sets the font used to display text in the control.
		/// </summary>
		[Category("Appearance"), Browsable(true), Description("Gets or sets the font used to display text in the control.")] 
		property System::Drawing::Font ^ Font
		{
			virtual void set(System::Drawing::Font ^ value) override
			{
				Control::Font::set(value);

				if(!this->DesignMode)
				{
					// Save previous context and make our context current
					HDC mhOldDC = wglGetCurrentDC();
					HGLRC mhOldGLRC = wglGetCurrentContext();
					wglMakeCurrent(mhDC, mhGLRC);

					// Delete old display lists
					glDeleteLists(base, 256);
					glDeleteLists(rasterbase, 256);
					
					// Create the font display lists
					SelectObject(mhDC, (HGDIOBJ)value->ToHfont());
					base = glGenLists(256);
					rasterbase = glGenLists(256);
					
					wglUseFontOutlines(mhDC, 0, 256, base, 0.0f, 0.0f, WGL_FONT_POLYGONS, NULL);
					wglUseFontBitmaps(mhDC, 0, 256, rasterbase);
					
					// Restore previous context
					wglMakeCurrent(mhOldDC, mhOldGLRC);

					Invalidate(); 
				}
			}
		}

	// Public methods.
	public:
		/// <summary>
		/// Resets the camera.
		/// </summary>
		System::Void ResetView();

	private:
		System::Void ControlResize(System::Object^  sender, System::EventArgs^  e);
		System::Void ControlMouseDown(System::Object^ sender, System::Windows::Forms::MouseEventArgs^ e);
		System::Void ControlMouseMove(System::Object^ sender, System::Windows::Forms::MouseEventArgs^ e);
		System::Void ControlMouseUp(System::Object^ sender, System::Windows::Forms::MouseEventArgs^ e);
		System::Void ControlMouseWheel(System::Object^ sender, System::Windows::Forms::MouseEventArgs^ e);
		System::Void ControlMouseDoubleClick(System::Object^ sender, System::Windows::Forms::MouseEventArgs^ e);

	protected:
		virtual property System::Windows::Forms::CreateParams^ CreateParams
		{
			System::Windows::Forms::CreateParams ^ get(void) override sealed
			{ 
				System::Windows::Forms::CreateParams^ cp = UserControl::CreateParams;
				cp->ClassStyle = cp->ClassStyle | CS_VREDRAW | CS_HREDRAW | CS_OWNDC;

				return cp; 
			}
		}
		virtual void OnPaint(System::Windows::Forms::PaintEventArgs^  e) override sealed;
		virtual void OnPaintBackground(System::Windows::Forms::PaintEventArgs^  e) override sealed;

	// Events
	public:
		delegate void RenderHandler(System::Object ^ sender, GLView::GLGraphics3D ^ Graphics);
		delegate void RenderDoneHandler(System::Object ^ sender);
		/// <summary>
		/// Occurs when the control is redrawn.
		/// </summary>
		[Category("Appearance"), Browsable(true)] 
		event RenderHandler ^ Render;
		/// <summary>
		/// Occurs after the control is redrawn.
		/// </summary>
		[Category("Appearance"), Browsable(true)] 
		event RenderDoneHandler ^ RenderDone;

	private: 
		System::Void InitializeComponent()
		{
			 this->Name = L"GLCanvas3D";
		}

		System::Void ResetViewport();

		Point3D GetOGLPos(int x, int y)
		{
			GLint viewport[4];
			GLdouble modelview[16];
			GLdouble projection[16];
			GLfloat winX, winY, winZ;
			GLdouble posX, posY, posZ;

			glGetDoublev(GL_MODELVIEW_MATRIX, modelview);
			glGetDoublev(GL_PROJECTION_MATRIX, projection);
			glGetIntegerv(GL_VIEWPORT, viewport);

			winX = (float)x;
			winY = (float)viewport[3] - (float)y;
			glReadPixels( x, int(winY), 1, 1, GL_DEPTH_COMPONENT, GL_FLOAT, &winZ );

			gluUnProject(winX, winY, winZ, modelview, projection, viewport, &posX, &posY, &posZ);

			return Point3D((float)posX, (float)posY, (float)posZ);
		}
	};
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Turkey Turkey
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions