C#, MDI and OpenGL

Hello, i hope you excuse my bad english, because i am from germany. I’m trying to open several mdichild windows in a main form. Every child window is an instance of class Subclass, that i defined. The code is based on NeHe tutorial with comes with Tao. In the constructor i wrote the complete initialization of OpenGL. Than i filled in code on resize and on paint and on close. But i cannot get it to work, i get error messages if i try to make the rendercontext current with makecurrent. I am stuck at this about 1 month. :frowning: If i delete the line: this.MdiParent = MainForm; than all works fine, painting is done and windows closed right. But than i have normal windows not MDI Windows like intended. I wonder why OpenGL get problems with MDI. Sorry to post such a long code, but i have no idear wether the error is.

 
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Runtime.InteropServices;
using System.Text;
using System.Windows.Forms;
using Tao.OpenGl;
using Tao.Platform.Windows;

namespace Test2
{
    public partial class SubForm : Form
    {
        private IntPtr hDC;                                              // Private GDI Device Context
        private IntPtr hRC;                                              // Permanent Rendering Context

        public SubForm(Form MainForm)
        {
            
            this.CreateParams.Classstyle = this.CreateParams.Classstyle |     // Redraw On Size, And Own DC For Window.
                User.CS_HREDRAW | User.CS_VREDRAW | User.CS_OWNDC;
            this.Setstyle(Controlstyles.AllPaintingInWmPaint, true);          // No Need To Erase Form Background
            this.Setstyle(Controlstyles.DoubleBuffer, true);                  // Buffer Control
            this.Setstyle(Controlstyles.Opaque, true);                        // No Need To Draw Form Background
            this.Setstyle(Controlstyles.ResizeRedraw, true);                  // Redraw On Resize
            this.Setstyle(Controlstyles.UserPaint, true);                     // We'll Handle Painting Ourselves

            InitializeComponent();

            Gdi.PIXELFORMATDESCRIPTOR pfd = new Gdi.PIXELFORMATDESCRIPTOR();    // pfd Tells Windows How We Want Things To Be
            pfd.nSize = (short)Marshal.SizeOf(pfd);                             // Size Of This Pixel Format Descriptor
            pfd.nVersion = 1;                                                   // Version Number
            pfd.dwFlags = Gdi.PFD_DRAW_TO_WINDOW |                              // Format Must Support Window
                Gdi.PFD_SUPPORT_OPENGL |                                        // Format Must Support OpenGL
                Gdi.PFD_DOUBLEBUFFER;                                           // Format Must Support Double Buffering
            pfd.iPixelType = (byte)Gdi.PFD_TYPE_RGBA;                           // Request An RGBA Format
            pfd.cColorBits = (byte)32;                                          // Select Our Color Depth
            pfd.cRedBits = 0;                                                   // Color Bits Ignored
            pfd.cRedShift = 0;
            pfd.cGreenBits = 0;
            pfd.cGreenShift = 0;
            pfd.cBlueBits = 0;
            pfd.cBlueShift = 0;
            pfd.cAlphaBits = 0;                                                 // No Alpha Buffer
            pfd.cAlphaShift = 0;                                                // Shift Bit Ignored
            pfd.cAccumBits = 0;                                                 // No Accumulation Buffer
            pfd.cAccumRedBits = 0;                                              // Accumulation Bits Ignored
            pfd.cAccumGreenBits = 0;
            pfd.cAccumBlueBits = 0;
            pfd.cAccumAlphaBits = 0;
            pfd.cDepthBits = 16;                                                // 16Bit Z-Buffer (Depth Buffer)
            pfd.cStencilBits = 0;                                               // No Stencil Buffer
            pfd.cAuxBuffers = 0;                                                // No Auxiliary Buffer
            pfd.iLayerType = (byte)Gdi.PFD_MAIN_PLANE;                          // Main Drawing Layer
            pfd.bReserved = 0;                                                  // Reserved
            pfd.dwLayerMask = 0;                                                // Layer Masks Ignored
            pfd.dwVisibleMask = 0;
            pfd.dwDamageMask = 0;
            
            hDC = User.GetDC(this.Handle);                                      // Attempt To Get A Device Context
            if (hDC == IntPtr.Zero)
            {                                                                   // Did We Get A Device Context?
                //Program.KillGLWindow();                                                 // Reset The Display
                MessageBox.Show("Can't Create A GL Device Context. Constructor ", "ERROR",
                    MessageBoxButtons.OK, MessageBoxIcon.Error);
                //return false;
            }

            int pixelFormat = Gdi.ChoosePixelFormat(hDC, ref pfd);                  // Attempt To Find An Appropriate Pixel Format
            if (pixelFormat == 0)
            {                                              // Did Windows Find A Matching Pixel Format?
                //Program.KillGLWindow();                                                 // Reset The Display
                MessageBox.Show("Can't Find A Suitable PixelFormat. Constructor", "ERROR",
                    MessageBoxButtons.OK, MessageBoxIcon.Error);
                //return false;
            }

            if (!Gdi.SetPixelFormat(hDC, pixelFormat, ref pfd))
            {                // Are We Able To Set The Pixel Format?
                //Program.KillGLWindow();                                                 // Reset The Display
                MessageBox.Show("Can't Set The PixelFormat. Constructor", "ERROR",
                    MessageBoxButtons.OK, MessageBoxIcon.Error);
                //return false;
            }

            hRC = Wgl.wglCreateContext(hDC);                                    // Attempt To Get The Rendering Context
            if (hRC == IntPtr.Zero)
            {                                            // Are We Able To Get A Rendering Context?
                //Program.KillGLWindow();                                                 // Reset The Display
                MessageBox.Show("Can't Create A GL Rendering Context. Constructor", "ERROR",
                    MessageBoxButtons.OK, MessageBoxIcon.Error);
                //return false;
            }

            SubForm_Resize(null, null);

            this.MdiParent = MainForm;
        }

        private void SubForm_Resize(object sender, EventArgs e)
        {
            if (!Wgl.wglMakeCurrent(hDC, hRC))
            {                                 // Try To Activate The Rendering Context
                //Program.KillGLWindow();                                                 // Reset The Display
                MessageBox.Show("Can't Activate The GL Rendering Context. Resize", "ERROR",
                    MessageBoxButtons.OK, MessageBoxIcon.Error);
                //return false;
            }

            if (this.Height == 0)
            {                                                   // Prevent A Divide By Zero...
                this.Height = 1;                                                     // By Making Height Equal To One
            }

            Gl.glViewport(0, 0, this.Width, this.Height);                                 // Reset The Current Viewport
            Gl.glMatrixMode(Gl.GL_PROJECTION);                                  // Select The Projection Matrix
            Gl.glLoadIdentity();                                                // Reset The Projection Matrix
            Glu.gluPerspective(45, this.Width / (double)this.Height, 0.1, 100);          // Calculate The Aspect Ratio Of The Window
            Gl.glMatrixMode(Gl.GL_MODELVIEW);                                   // Select The Modelview Matrix
            Gl.glLoadIdentity();

            if (!Wgl.wglMakeCurrent(IntPtr.Zero, IntPtr.Zero))
            {             // Are We Able To Release The DC and RC Contexts?
                MessageBox.Show("Release Of DC And RC Failed. Resize ", "SHUTDOWN ERROR",
                    MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
        }

        private void SubForm_FormClosing(object sender, FormClosingEventArgs e)
        {
            if (!Wgl.wglDeleteContext(hRC))
            {                                // Are We Able To Delete The RC?
                MessageBox.Show("Release Rendering Context Failed. Closing ", "SHUTDOWN ERROR",
                    MessageBoxButtons.OK, MessageBoxIcon.Error);
            }

            hRC = IntPtr.Zero;                                 // Set RC To Null
        }

        private void SubForm_Paint(object sender, PaintEventArgs e)
        {
            if (!Wgl.wglMakeCurrent(hDC, hRC))
            {                                 // Try To Activate The Rendering Context
                //Program.KillGLWindow();                                                 // Reset The Display
                MessageBox.Show("Can't Activate The GL Rendering Context. Paint", "ERROR",
                    MessageBoxButtons.OK, MessageBoxIcon.Error);
                //return false;
            }

            Gl.glClear(Gl.GL_COLOR_BUFFER_BIT | Gl.GL_DEPTH_BUFFER_BIT);        // Clear Screen And Depth Buffer
            Gl.glLoadIdentity();                                                // Reset The Current Modelview Matrix
            Gl.glTranslatef(-1.5f, 0, -6);                                      // Move Left 1.5 Units And Into The Screen 6.0
            Gl.glBegin(Gl.GL_TRIANGLES);                                        // Drawing Using Triangles
            Gl.glVertex3f(0, 1, 0);                                         // Top
            Gl.glVertex3f(-1, -1, 0);                                       // Bottom Left
            Gl.glVertex3f(1, -1, 0);                                        // Bottom Right
            Gl.glEnd();                                                         // Finished Drawing The Triangle
            Gl.glTranslatef(3, 0, 0);                                           // Move Right 3 Units
            Gl.glBegin(Gl.GL_QUADS);                                            // Draw A Quad
            Gl.glVertex3f(-1, 1, 0);                                        // Top Left
            Gl.glVertex3f(1, 1, 0);                                         // Top Right
            Gl.glVertex3f(1, -1, 0);                                        // Bottom Right
            Gl.glVertex3f(-1, -1, 0);                                       // Bottom Left
            Gl.glEnd();
            // Done Drawing The Quad

            Gdi.SwapBuffers(hDC);                                           // Swap Buffers (Double Buffering)

            if (!Wgl.wglMakeCurrent(IntPtr.Zero, IntPtr.Zero))
            {             // Are We Able To Release The DC and RC Contexts?
                MessageBox.Show("Release Of DC And RC Failed. Paint ", "SHUTDOWN ERROR",
                    MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
            
        }
    }
}

Thx, Therion

Ich hab keine Ahnung ob es damit zusammen hängt, und ob diese Sachen unter C# überhaupt noch relevant sind, aber in meinen MFC Programmen hab ich vor dem Erstellen des Fensters (in PreCreateWindow) den Style mit “WS_CLIPCHILDREN | WS_CLIPSIBLINGS” ergänzt.

mfg,
Shinta

Ich habe gerade nachgesehn, WS_CLIPCHILDREN | WS_CLIPSIBLINGS beziehen sich beide auf das Zeichnen und sparen z.b. einen Bereich aus. Hier scheint es Probleme mit dem DC und RC zu geben weil diese nicht aktiviert werden können.

public class MyPanel : Panel
{
  public MyPanel()
  {
    this.SetStyle( ControlStyles.AllPaintingInWmPaint, true);
    this.SetStyle( ControlStyles.OptimizedDoubleBuffer, false);
    this.SetStyle( ControlStyles.Opaque, true);
    this.SetStyle( ControlStyles.ResizeRedraw, true);
    this.SetStyle( ControlStyles.UserPaint, true);
  }

  protected override CreateParams CreateParams
  {
    get
    {
      CreateParams cp=base.CreateParams;
      cp.ClassStyle=cp.ClassStyle | User.CS_VREDRAW | User.CS_HREDRAW  | User.CS_OWNDC;
      return cp;
    }
  }
}

Bau einfach diese Panel-Ableitung in dein Fenster (SubForm), hol dir den DC von Panel und fertig.
(Der Teil, im Konstruktor von SubForm, vor ‘InitializeComponent();’ kann weg.)

Danke schonmal für die Tips :slight_smile: Also ich habe die MyPanel genauso übernohmen. Ich habe dann in der Subform Class eine Instanz davon abgeleitet: private MyPanel panel = new MyPanel();
Dann habe ich
hDC = User.GetDC(this.Handle); durch
hDC = User.GetDC(panel.Handle);
ersetzt.
Fenster werden erzeugt und können auch wieder entfernt werden, nur leider sind die Fenster alle grau. Wenn man drüber nachdenkt auch logisch, da bei GetDC ein Handel auf die Zeichenfläche übergeben wird, also hier das Panel. Nur klappt das Zeichnen irgendwie nicht. Etwas fehlt noch :slight_smile:
Ich habe in CreateParams noch folgende Zeile eingefügt:
cp.Style = 0 | 0xC00000 | 0x80000 | 0x40000 | 0x20000 | 0x10000 | 0x2000000 | 0x4000000; // WS_CLIPCHILDREN, WS_CLIPSIBLINGS

Dies hilft leider auch nicht, aber hatte mal wo gelesen das WS_CLIPCHILDREN, WS_CLIPSIBLINGS wichtig sind für OpenGL. Ausserdem hast du es vorher soga rnoch erwähnt, hehe.

So mittlerweile habe ich das mit dem Panel hinbekommen aber ohne nur mit dem normalen Panel. Leider zeichnet sich ein drunter liegendes Fenster nicht neu wenn man einem oben drüber fährt, dann fehlt da was… SEtze ich die obigen Sachen in den Constructor und nehme meine eigene Panel Klasse, dann verschmiert die Grafik an den betreffenden Stellen mit der Grafik die drübergezogen wurde. Setze ich CreateParams hat das keine Auswirkung. Ich muss also dafür sorgen, dass sich drunter liegende Fenster richtig neuzeichnen sobald ein drüberliegendes sie nicht mehr verdeckt.

Okay, ich hab vielleicht ein bisschen wenig dazu ausgeführt: Als Erstes zeichnest du ein ganz normaler Panel in dein SubForm (mit dem Designer) und konfigurierst es so wie die Opengl-Anzeigen verhalten soll (Name vergeben, Anchor setzten oder Dock=FILL etc.).
Danach änderst du im Code das ‘Panel’ zu ‘MyPanel’…
Als letztes musst du nur noch den DC vom Handle des Panels holen (wie oben schon richtig zu sehen ist).

Mehr braucht es nicht… ich hab auch nicht mehr gemacht (mal abgesehen davon, dass ich mir erst noch ein MDI-Fenster geWizardt hab).

Wenn du den Quelltext des gesamten Projekts haben willst, msg mir eine ladungsfähigen E-Mail-Adresse.

Anyway, and sorry to all who can’t read the german texts above, I recommend to use OpenGL-Controls in MDI client windows.
e.g.:

  • ‘SimpleOpenGlControl’ of the Tao framework ( http://www.taoframework.com ) or[*]‘OpenGLControl’ of the C# OpenGL framework ( http://www.csharpopenglframework.com ) (You have to add/insert ‘renderingContext.MakeCurrent();’ to the OnPaint-Methode to get it work with multiple OpenGL-Controls/OpenGL-Contexts.)

This topic was automatically closed 183 days after the last reply. New replies are no longer allowed.