Library tutorials & articles

OpenGL and C# - Part 1

An OpenGL Control

What we need to do now is add a class named OurView. Make it a derived class from OpenGLControl. I will show you the code for the class now.

using System;
using System.Drawing;
using System.Windows.Forms;
using CsGL.OpenGL;
namespace SimpleOpenGL
{
    public class OurView : OpenGLControl
    {
        public OurView(): base()
        {
            this.KeyDown += new KeyEventHandler(OurView_OnKeyDown);
        }
        public override void glDraw()
        {    
            GL.glClear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT); // Clear The Screen And The Depth Buffer    
            GL.glLoadIdentity();                 // Reset The Current Modelview Matrix        
            // TODO: Draw a box or something
//             this.SwapBuffer(); // swap Buffers
        }
        protected override void InitGLContext()
        {
            GL.glShadeModel(GL.GL_SMOOTH);         // Set Smooth Shading                
            GL.glClearColor(0.0f, 0.0f, 0.0f, 0.5f);     // BackGround Color        
            GL.glClearDepth(1.0f);                 // Depth buffer setup            
            GL.glEnable(GL.GL_DEPTH_TEST);         // Enables Depth Testing            
            GL.glDepthFunc(GL.GL_LEQUAL);             // The Type Of Depth Test To Do    
            GL.glHint(GL.GL_PERSPECTIVE_CORRECTION_HINT, GL.GL_NICEST);     /* Really Nice Perspective Calculations */    
        }
        protected override void OnSizeChanged(EventArgs e)
        {
            base.OnSizeChanged(e);
       
            Size s = Size;
            double aspect_ratio = (double)s.Width /(double) s.Height;
            GL.glMatrixMode(GL.GL_PROJECTION); // Select The Projection Matrix
            GL.glLoadIdentity(); // Reset The Projection Matrix
           
            // Calculate The Aspect Ratio Of The Window
            GL.gluPerspective(45.0f, aspect_ratio, 0.1f, 100.0f);
   
            GL.glMatrixMode(GL.GL_MODELVIEW); // Select The Modelview Matrix
            GL.glLoadIdentity();// Reset The Modelview Matrix
        }
        protected void OurView_OnKeyDown(object Sender, KeyEventArgs kea)
        {
            if (kea.KeyCode == Keys.Q && kea.Modifiers == Keys.Shift)
            {
                Application.Exit();
            }
        }
    }
}

You may notice that this is almost the base code from NeHe. And yes it is I created it with the NeHe base code in mind. I won’t go for every gl function in detail you can read here, lesson 1 & 2 for that.

Now we have the control we can add it to our form. Add this in the class

private SimpleOpenGL.OurView view;

Ok add this after the InitializeComponent function.

this.view = new SimpleOpenGL.OurView();
this.view.Parent = this;
this.view.Dock = DockStyle.Fill; // Will fill whole form

You can now try to run your form. Everything is running perfect. But there is one more thing our form is only render once. And when you resize it, it will render another time. To solve this problem we’re going to add a thread which will render the scene over and over again (how it should).

Ok first thing to do is add a thread. Put this underneath the other declarations.

private static Thread thrOpenGL;

Then underneath the view properties.

thrOpenGL = new Thread(new ThreadStart(OpenGL_Start));
thrOpenGL.Start();
Then the function OpenGL_Start.
private void OpenGL_Start()
{
    for (;;) // infinity loop for rendering
    {
        this.view.Refresh();
    }
}

If you would run the application now you might notice that when you close the form you program isn’t really exit cause the thread is still running to solve this we add this code at the end of the Dispose function. But for people who don’t use the Visual Studio .Net I will show you the whole function.

protected override void Dispose( bool disposing )
{
    if( disposing )
    {
        if (components != null)
        {
            components.Dispose();
        }
    }
    base.Dispose( disposing );
    // Abort the OpenGL Thread
    // otherwise it will last rendering forever
    thrOpenGL.Abort();
}

We are done with our OpenGL control now but it is hard to show off to your friends when you only have a black window. Like this.BackColor = Color.Black;in the main form constructor will do the same thing.

Comments

  1. 07 Oct 2009 at 09:29

    Thanks for the tutorial, unfortunately it does not work for me. All I see is white background with a red cross of which I don't know where it comes from... Thanks for any help...

  2. 12 Sep 2009 at 20:54

    Strange, I've added a menu in the top of the window and now everything works perfectly :) thx for the tutorial. Without it I would never start. We Polish used to say "The first step is the hardest"

  3. 10 Sep 2009 at 23:49

    First of all there is no csgl-base.dll in a package csgl.dll.zip downloaded from project site. Secound of all can anybody tell me why it doesn't work? Sometimes I have to change widnow size to see the scene, sometimes it never showes up :| why? What I'm doing wrong? uffff F1 F1 F1 HELP!

  4. 01 Sep 2009 at 16:27

    the solution i know is:

        CheckForIllegalCrossThreadCalls = false;
    

    which is simpler

  5. 01 Sep 2009 at 16:26

    the solution i know is:

        CheckForIllegalCrossThreadCalls = false;
    

    which is simpler

  6. 13 Aug 2009 at 11:01

    private void OpenGL_Start() { if( this.view.InvokeRequired) { ThreadStart aDelegate = new ThreadStart(this.view.Refresh); for( ; ; ) { Thread.Sleep(1000); if( !thrOpenGL.IsAlive ) return; this.Invoke(aDelegate); } } else { for( ; ; ) { // infinity loop for rendering Thread.Sleep(1000); this.view.Refresh(); } } }

  7. 08 Aug 2009 at 14:14

    (sorry for not marking the code as code in the comment above...)

    Hi Johnny, Still there? I know it's been a while since 2003... But if you are still around, or anyone else, I have a question:

    How do I draw two separate sets of drawing in parallel? I want to draw an Anaglyph. Let's say, a blue cube and a red cude. each in a different color and at a slightly different angle acording to two POV (points of view).

    Any suggestions?

    All the best. Amir

  8. 08 Aug 2009 at 14:08

    Hi All, I ran into some trouble with the thread above, but, I found a solution... Aperantly, while using Visual Studio 2008 such a cross thread action is considered unsafe. Anyway, the "Invoke" method can take care of that with just a few lines of code:

    private void OpenGL_Start() { if( this.view.InvokeRequired) { ThreadStart aDelegate = new ThreadStart(this.view.Refresh); for( ; ; ) { Thread.Sleep(1000); if( !thrOpenGL.IsAlive ) return; this.Invoke(aDelegate); } } else { for( ; ; ) { // infinity loop for rendering Thread.Sleep(1000); this.view.Refresh(); } } }

    The 'if' statement check to see if the action is done on the current thread or not and uses the "invoke" when necessary.

    I hope I saved someone the 60 minutes it took me... ;-)

Leave a comment

Sign in or Join us (it's free).

Johnny I'm doing first year Informatica at academy of Amsterdam

Related podcasts

  • Object-Oriented Programming in Ruby

    In this episode, I talk with Scott Bellware about object-oriented programming in Ruby, and Ruby's object model. This is taken from a private conversation, and the audio quality suffers at times. Much thanks to Scott for allowing this to be released.This episode of the Alt.NET Podcast is bro...

We'd love to hear what you think! Submit ideas or give us feedback