#pragma once
#include <windows.h>
#include <GL/gl.h>
using namespace System;
using namespace System::Drawing;
using namespace System::ComponentModel;
using namespace System::Windows::Forms;
namespace GLView {
// Forward class declarations
ref class GLGraphics;
ref class GLPerformanceTimer;
/// <summary>
/// Represents a 2D drawing canvas utilizing OpenGL.
/// </summary>
[ToolboxBitmap(GLView::GLCanvas2D::typeid)]
public ref class GLCanvas2D : public System::Windows::Forms::UserControl
{
private:
value class GLPointFloat
{
float X;
float Y;
};
value class GLGlyphMetrics
{
float gmfBlackBoxX;
float gmfBlackBoxY;
GLPointFloat gmfptGlyphOrigin;
float gmfCellIncX;
float gmfCellIncY;
};
// Constructor/destructor
public:
GLCanvas2D();
protected:
~GLCanvas2D();
// Enums
public:
enum class SelectMode
{
None,
PointPick,
Line,
Circle,
Rectangle,
ShadedRectangle
};
ref class GLGraphics;
// Member variables
private:
Drawing::Color mBackColor;
HDC mhDC;
HGLRC mhGLRC;
bool mIsAccelerated;
PointF mCameraPosition;
bool mPanning;
bool mSelecting;
Point mLastMouse;
float mZoomFactor;
Drawing::Point mSelPt1, mSelPt2;
Drawing::RectangleF mLimits;
bool mShowGrid;
bool mShowAxes;
float mGridSpacing;
Drawing::Color mMinorGridColor;
Drawing::Color mMajorGridColor;
Drawing::Color mAxisColor;
bool mDynamicGrid;
GLPerformanceTimer ^ mTimer;
unsigned long mRenderTime;
unsigned long mElapsedTime;
int mFrameCount;
int mFPS;
bool mAntiAlias;
GLuint base, rasterbase;
public:
/// <summary>
/// Determines whether hardware acceleration is enabled.
/// </summary>
[Category("Behavior"), Browsable(false)]
property bool IsAccelerated
{
virtual bool get(void) { return mIsAccelerated; }
}
/// <summary>
/// Gets or sets the mouse selection mode.
/// </summary>
[Category("Behavior"), Browsable(true)]
property SelectMode SelectionMode;
/// <summary>
/// Determines whether zooming and panning with the mouse is allowed.
/// </summary>
[Category("Behavior"), Browsable(true)]
property bool AllowZoomAndPan;
/// <summary>
/// Determines whether grid lines are visible.
/// </summary>
[Category("Appearance"), Browsable(true)]
property bool ShowGrid
{
virtual bool get(void) { return mShowGrid; }
virtual void set(bool value) { mShowGrid = value; Invalidate(); }
}
/// <summary>
/// Determines whether axes are visible.
/// </summary>
[Category("Appearance"), Browsable(true)]
property bool ShowAxes
{
virtual bool get(void) { return mShowAxes; }
virtual void set(bool value) { mShowAxes = value; Invalidate(); }
}
/// <summary>
/// Determines whether grid spacing is dynamically determined.
/// </summary>
[Category("Appearance"), Browsable(true)]
property bool DynamicGrid
{
virtual bool get(void) { return mDynamicGrid; }
virtual void set(bool value) { mDynamicGrid = value; Invalidate(); }
}
/// <summary>
/// Gets or sets the grid spacing.
/// </summary>
[Category("Appearance"), Browsable(true)]
property float GridSpacing
{
virtual float get(void) { return mGridSpacing; }
virtual void set(float value) { mGridSpacing = value; Invalidate(); }
}
/// <summary>
/// Gets or sets the color of minor gridlines.
/// </summary>
[Category("Appearance"), Browsable(true)]
property Drawing::Color MinorGridColor
{
virtual Drawing::Color get(void) { return mMinorGridColor; }
virtual void set(Drawing::Color value) { mMinorGridColor = value; Invalidate(); }
}
/// <summary>
/// Gets or sets the color of major gridlines.
/// </summary>
[Category("Appearance"), Browsable(true)]
property Drawing::Color MajorGridColor
{
virtual Drawing::Color get(void) { return mMajorGridColor; }
virtual void set(Drawing::Color value) { mMajorGridColor = value; Invalidate(); }
}
/// <summary>
/// Gets or sets the color of axes.
/// </summary>
[Category("Appearance"), Browsable(true)]
property Drawing::Color AxisColor
{
virtual Drawing::Color get(void) { return mAxisColor; }
virtual void set(Drawing::Color value) { mAxisColor = value; Invalidate(); }
}
/// <summary>
/// Determines whether lines are anti-aliased.
/// </summary>
[Category("Appearance"), Browsable(true)]
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>
/// Gets or sets the color of selection lines.
/// </summary>
[Category("Appearance"), Browsable(true)]
property Drawing::Color SelectionColor;
/// <summary>
/// Gets the limits of all drawing objects on the canvas.
/// </summary>
[Category("Behavior"), Browsable(false)]
property Drawing::RectangleF Limits
{
virtual Drawing::RectangleF get(void) { return mLimits; }
}
/// <summary>
/// Gets the last render time in milliseconds.
/// </summary>
[Category("Performance"), Browsable(false)]
property unsigned long RenderTime
{
virtual unsigned long get(void) { return mRenderTime; }
}
/// <summary>
/// Gets the count of frames per second.
/// </summary>
[Category("Performance"), Browsable(false)]
property int FPS
{
virtual int get(void) { return mFPS; }
}
/// <summary>
/// Returns the display list used to draw vector text.
/// </summary>
[Category("Appearance"), Browsable(false)]
property GLuint VectorListBase
{
virtual GLuint get(void) { return base; }
}
/// <summary>
/// Returns the display list used to draw raster text.
/// </summary>
[Category("Appearance"), Browsable(false)]
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)]
property System::Drawing::Font ^ Font
{
virtual void set(System::Drawing::Font ^ value) override
{
Control::Font::set(value);
// 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>
/// Converts the given point from world coordinates to screen coordinates.
/// </summary>
Drawing::Point WorldToScreen(float x, float y)
{
return Drawing::Point((int)((x - mCameraPosition.X) / mZoomFactor) + ClientRectangle.Width / 2,
-(int)((y - mCameraPosition.Y) / mZoomFactor) + ClientRectangle.Height / 2);
}
/// <summary>
/// Converts the given point from world coordinates to screen coordinates.
/// </summary>
Drawing::Point WorldToScreen(Drawing::PointF pt) { return WorldToScreen(pt.X, pt.Y); }
/// <summary>
/// Converts the given vector from world coordinates to screen coordinates.
/// </summary>
Drawing::Size WorldToScreen(Drawing::SizeF pt)
{
Drawing::Point pt1 = WorldToScreen(0.0f, 0.0f);
Drawing::Point pt2 = WorldToScreen(pt.Width, pt.Height);
return Drawing::Size(pt2.X - pt1.X, pt2.Y - pt1.Y);
}
/// <summary>
/// Converts the given point from screen coordinates to world coordinates.
/// </summary>
Drawing::PointF ScreenToWorld(int x, int y)
{
return Drawing::PointF((float)(x - ClientRectangle.Width / 2) * mZoomFactor + mCameraPosition.X,
-(float)(y - ClientRectangle.Height / 2) * mZoomFactor + mCameraPosition.Y);
}
/// <summary>
/// Converts the given point from screen coordinates to world coordinates.
/// </summary>
Drawing::PointF ScreenToWorld(Drawing::Point pt) { return ScreenToWorld(pt.X, pt.Y); }
/// <summary>
/// Converts the given vector from screen coordinates to world coordinates.
/// </summary>
Drawing::SizeF ScreenToWorld(Drawing::Size pt)
{
Drawing::PointF pt1 = ScreenToWorld(0, 0);
Drawing::PointF pt2 = ScreenToWorld(pt.Width, pt.Height);
return Drawing::SizeF(pt2.X - pt1.X, pt2.Y - pt1.Y);
}
/// <summary>
/// Returns the coordinates of the viewport in world coordinates.
/// </summary>
Drawing::RectangleF GetViewPort()
{
Drawing::PointF bl = ScreenToWorld(ClientRectangle.Left, ClientRectangle.Bottom);
Drawing::PointF tr = ScreenToWorld(ClientRectangle.Right, ClientRectangle.Top);
return Drawing::RectangleF(bl.X, bl.Y, tr.X - bl.X, tr.Y - bl.Y);
}
/// <summary>
/// Sets the viewport to the given model coordinates.
/// </summary>
System::Void SetView(float x1, float y1, float x2, float y2)
{
float h = Math::Abs(y1 - y2);
float w = Math::Abs(x1 - x2);
mCameraPosition = PointF((x1 + x2) / 2, (y1 + y2) / 2);
if ((ClientRectangle.Height != 0) && (ClientRectangle.Width != 0))
mZoomFactor = Math::Max(h / (float)(ClientRectangle.Height), w / (float)(ClientRectangle.Width));
else
mZoomFactor = 1;
}
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 void OnPaint(System::Windows::Forms::PaintEventArgs^ e) override sealed;
// Events
public:
delegate void RenderHandler(System::Object ^ sender, GLView::GLGraphics ^ Graphics);
delegate void MousePickHandler(System::Object ^ sender, Drawing::Point pt);
delegate void MouseSelectHandler(System::Object ^ sender, Drawing::Point pt1, Drawing::Point pt2);
/// <summary>
/// Occurs when the control is redrawn.
/// </summary>
[Category("Appearance"), Browsable(true)]
event RenderHandler ^ Render;
/// <summary>
/// Occurs when the user picks a point with the mouse.
/// </summary>
[Category("Mouse"), Browsable(true)]
event MousePickHandler ^ MousePick;
/// <summary>
/// Occurs when the user selects a region with the mouse.
/// </summary>
[Category("Mouse"), Browsable(true)]
event MouseSelectHandler ^ MouseSelect;
};
}