This project is read-only.

SharpGL Fundamentals

This page details the most fundamental concepts of SharpGL that you must be aware of to begin developing applications.

Naming Conventions

OpenGL constants are named in exactly the same way as they are in OpenGL and are constant members of the OpenGL class. As an example, the constants below:

//  Two OpenGL constants.
GL_TRIANGLES
GLU_TESS_COMBINE

Would be written as:

//  Two OpenGL constants.
OpenGL.GL_TRIANGLES
OpenGL.GLU_TESS_COMBINE

OpenGL functions are named in exactly the same way as they are in OpenGL - except that the 'gl' prefix is removed. For example, the calls below:

//  Set the line width and point size.
glLineWidth(3.0f);
glPointSize(2.0f);

Would be written as:

//  Get a reference to the OpenGL object.
OpenGL gl = openGLCtrl1.OpenGL;

//  Set the line width and point size.
gl.LineWidth(3.0f);
gl.PointSize(2.0f);

There is an exception to this rule. Parameter type postfixes are always removed from OpenGL function names. The appropriate function is called always based on the types used. For example, the calls below:

//  Set the color.
glColor3f(0.5f, 0.5f, 0.5f);

//  Output some vertices.
glVertex3f(2.0f, 3.0f 4.0f);
glVertex4f(2.0f, 1.0f, 10.0f, 1.0f);

Would be written as:

//  Set the color.
gl.Color3(0.5f, 0.5f, 0.5f);

//  Output some vertices.
gl.Vertex3(2.0f, 3.0f 4.0f);
gl.Vertex4(2.0f, 1.0f, 10.0f, 1.0f);

The number of parameters IS included at the end of the function name, just as it is in standard OpenGL calls. This is because in some cases, we still we need to know this - for example when calling glVertex3fv or glVertex4fv we need to know how many items in an array we are passing. Because of this, to maintain consistency if the OpenGL function has a number at the end of it, so does the SharpGL wrapper function.

Calling OpenGL Functions

There are two different ways that OpenGL functions can be called.

1. Direct OpenGL Calls

You an use the OpenGL object directly to make OpenGL calls. Every function in OpenGL and all extension functions are included in the OpenGL object. All constants are also defined. In this case, a section of code as below:

//  Set the polygon mode.
glPolygonMode(GL_FRONT, GL_FILL);

Would become:

//  Get the OpenGL object.
OpenGL gl = openGLControl.OpenGL;

//  Set the polygon mode.
gl.PolygonMode(OpenGL.GL_FRONT, OpenGL.GL_FILL);

This is the most straightforward way to make OpenGL calls, and makes porting existing OpenGL code very simple.

2. Direct OpenGL calls with Wrapped Enumerations

Almost all OpenGL functions that take some kind of uint, such as glPolygonMode have overloads that provide enumerations as parameters. For example, the call below:

//  Set the polygon mode.
glPolygonMode(GL_FRONT, GL_FILL);

Could be written as:

//  Get the OpenGL object.
OpenGL gl = openGLControl.OpenGL;

//  Set the polygon mode.
gl.PolygonMode(PolygonFace.Front, PolygonMode.Fill);

This approach has the benefit that when you are writing the code, you have Intellisense to help you pick the appropriate parameter from the acceptable parameters only. However, this code is less alike standard OpenGL calls, so it may take more work to port existing calls to this style.

Render Contexts

A Render Context is an object that manages the underlying Render Context Handle. Until a Render Context is created no OpenGL functions will work - and no extensions will be loaded. Calling OpenGL.Create will create the Render Context - once this is done extensions can be used but before this point they will not work.

Last edited Feb 20, 2012 at 2:07 PM by dwmkerr, version 4

Comments

TimJSwan Nov 10, 2014 at 11:09 PM 
Near the top of the tutorial you have
// Get a reference to the OpenGL object.
OpenGL gl = openGLCtrl1.OpenGL;

However, I don't have access to this ctrl object.

fvapres Jun 24, 2014 at 7:26 AM 
In VC#Express, I went to create a project and used the Online Template and searched for SharpGL. When I clicked OK, it set up a project for VC# that had a form with a control on it. The form was already defined with 3 functions, which IIRC were called

private void OpenGLControl_Draw(object sender, RenderEventArgs args)
private void OpenGLControl_Initialized(object sender, EventArgs e)
private void OpenGLControl_Resized(object sender, EventArgs e)

The first thing I did was rename the OpenGLControl to glRC (short for glRenderingControl) and renamed the functions in all the various places for simple customization. As I would be using the old-fashioned drawing methods of glBegin/glEnd, I reverted the controls OpenGL to 2_1 and upped the Desired FPS of the control from 20 to 1000. As I understand it, this is the framerate the control will attempt to achieve by setting the delay on a timer that fires the Draw function. To get the highest framerate possible, I use 1000, even though my FRAPS indicates 60-70 as well as my FPS counter code, the SharpGL FPS shows 1000. Lowering it to 800 shows 800 in the SharpGL FPS counter, but my code calculates 60-70 still. When I go to 60 or lower, I get about 50-75% of the desired number. Setting to 60 gets me 40FPS, setting to 40 gets me 30...

In the Resized function, this is my code (keep in mind, I'm making a 2D program with no depth)
private void glRC_Resized(object sender, EventArgs e) {
OpenGL gl = glRC.OpenGL;
gl.MatrixMode(OpenGL.GL_PROJECTION);
gl.LoadIdentity();
gl.Ortho(0, DU.DU_Size, DU.DU_Size, 0, 0, 1);
gl.MatrixMode(OpenGL.GL_MODELVIEW);
gl.LoadIdentity();
}
My initialization code:
private void glRC_Initialized(object sender, EventArgs e)
{
//reference to opengl
gl = glRC.OpenGL;
//2D only - forget depth buffer
gl.Disable(OpenGL.GL_DEPTH_TEST);
//set up smoothing options for AA
gl.ShadeModel(OpenGL.GL_SMOOTH);
gl.Enable(OpenGL.GL_POINT_SMOOTH);
gl.Enable(OpenGL.GL_LINE_SMOOTH);
gl.Hint(OpenGL.GL_LINE_SMOOTH_HINT, OpenGL.GL_DONT_CARE);
gl.Hint(OpenGL.GL_POINT_SMOOTH_HINT, OpenGL.GL_NICEST);
gl.Hint(OpenGL.GL_POLYGON_SMOOTH_HINT, OpenGL.GL_NICEST);
//set up alpha blending
gl.Enable(OpenGL.GL_BLEND);
gl.BlendFunc(OpenGL.GL_SRC_ALPHA, OpenGL.GL_ONE_MINUS_SRC_ALPHA);
//setup texture blending
gl.Enable(OpenGL.GL_TEXTURE_2D);
gl.TexEnv(OpenGL.GL_TEXTURE_ENV, OpenGL.GL_TEXTURE_ENV_MODE, OpenGL.GL_MODULATE);
//set the matrix mode
gl.MatrixMode(OpenGL.GL_PROJECTION);
//init sprite-based font
fnt = new GLFont(Application.StartupPath + "\\Data\\Fonts\\", "Nina.xml", gl);
//call other intialization functions
InitDisplays();
//set the background clear color and prepare to render the first frame
gl.ClearColor(Settings.BGColor.R, Settings.BGColor.G, Settings.BGColor.B, 1);
}

finally, my Draw code:
private void glRC_Draw(object sender, RenderEventArgs args)
{
//define variable for displaying mouse location on click
GLRectangle MousePos;
// Get the OpenGL object.
OpenGL gl = glRC.OpenGL;
gl.Clear(OpenGL.GL_COLOR_BUFFER_BIT | OpenGL.GL_STENCIL_BUFFER_BIT);
//if not getting data externally, fake it
if (!PauseDataFaking)
{
Bank.Step();
Pitch.Step();
Heading.Step();
IAS.Step();
Slip.Step();
}
//load the identity matrix and set the color to fully opaque white
gl.LoadIdentity();
gl.Color(1.0f, 1.0f, 1.0f, 1.0f);
//loop through the displays and render them in their own matricies
for (int a = 0; a < Displays.Count; a++) {
if (Displays[a].Inited)
{
DUtils.glPushMatrix(gl, "glRC.Draw()");
Displays[a].Draw(gl);
DUtils.glPopMatrix(gl, "glRC.Draw()");
}
}
//show the mouse cursor on the screen if needed
if (mX > -1 || mY > -1)
{
MouseCounter++;
MousePos = new GLRectangle(mX, mY, 20, 20, Color.White, "MousePos");
DUtils.DrawGLRectangle(gl, MousePos, 0);
DUtils.glEnd(gl, 0, true, "glRC.Draw.MousePos");
}
//actual FPS performance calculations
cFrame = Environment.TickCount * 0.001f;
FrameCtr++;
if (cFrame - pFrame >= 0.2f)
{
FPS = FrameCtr * (1 / (cFrame - pFrame));
pFrame = cFrame;
FrameCtr = 0;
}
gl.Flush();
}


You'll see references to DUtils...I have a custom class that I use to keep my calls to gl.Begin and gl.End in check to ensure it all goes smoothly. It keeps track of the drawing state and only calls glEnd and glBegin when needed. I store the Triangles and Lines in class objects and draw them in sequence, but sometimes, I may draw 100 lines in a row and instead of calling glBegin/glEnd for each, it knows that its already been drawing lines and doesn't need to call glEnd until a different object type like Triangles or Quads are going to be drawn. When I reset the texture to bind or the color, it also calls glEnd then restarts the glBegin command with the same object type. Doing this has taken my program from 10FPS actual back up to 70...

MichaelBate Feb 15, 2013 at 11:20 PM 
This section does not describe how an initial Viewport is set up or what the clipping region is initially set to.

In the FormSimpleDrawing sample. I do not see OpenGL.Create (or any Create function) being called, yet the objects are displayed. It appears that ViewPort has been set to the surface of the control Calling Ortho seems to hide the triangle but leave the rectangle unchanged. Changing the Ortho parameter values has no effect on the rectangle.

Also I have had no luck substituting simple code to draw a polygon (via gl.Begin(OpenGL.GL_POLYGON);) in the FrameSimpleDrawing sample.