Help with Tao in c#[Solved]

Started by
4 comments, last by crackers 16 years, 2 months ago
Hi everybody, I've been reading the book "OpenGl Game Developing" by Chris Seddon and translating the code to c# with Tao and I'm running into some troubles in Chapter 2 so I wanted to know if somebody could help me out a bit :D. When using the SimpleOpenglControl provided with the framework I had no problem (other than buggy graphics, but I believe that's because of the integrated video card), but when I try my own Initialization of OpenGL, It seems like it creates the contexts just fine but It won't draw in the Panel, so I believe it has something to do with the Raster class:


class Raster 
    {
        //Necesitamos Importar los metodos para obtener y liberar el 
        //Device Context
        #region Importaciones

        /// <summary>
        /// IMporta el metodo GetDC(Intptr hWnd) del GDI
        /// </summary>
        /// <param name="hWnd">El handle de una ventana</param>
        /// <returns></returns>
        [DllImport("user32.dll", EntryPoint = "GetDC")]
        public static extern IntPtr GetDC(IntPtr hWnd);

        /// <summary>
        /// Este importa el ReleaseDC que libera el dispositivo
        /// </summary>
        /// <param name="hWnd">El Handle de la ventana</param>
        /// <param name="hDC">El dispositivo q se va a liberar</param>
        /// <returns></returns>
        [DllImport("user32.dll", EntryPoint = "ReleaseDC")]
        public static extern bool ReleaseDC(IntPtr hWnd, IntPtr hDC);

        #endregion

        #region MiembrosPrivados

        private Control _renderTarget;

        private byte _colorBits;
        private byte _depthBits;

        //El tipo Intpts es para handles o para referencias
        private IntPtr _handleDeviceContext;
        private IntPtr _handleRenderContex;        

        #endregion

        #region Propiedades

        public byte ColorBits 
        {
            set 
            {
                _colorBits = value;
            }
            get 
            {
                return _colorBits;
            }   
        }

        public byte DepthBits 
        {
            set
            {
                _depthBits = value;
            }
            get
            {
                return _depthBits;
            }   
        }

        public IntPtr DeviceContext 
        {
            set
            {
                _handleDeviceContext = value;
            }
            get
            {
                return _handleDeviceContext;
            }   
        }

        public IntPtr RenderContext
        {
            set
            {
                _handleRenderContex = value;
            }
            get
            {
                return _handleRenderContex;
            }
        }

        #endregion

        #region Constructor

        /// <summary>
        /// Inicializa varias cosas
        /// </summary>
        public Raster()         
        {
            ColorBits = 24;
            DepthBits = 32;

            RenderContext = IntPtr.Zero;
            DeviceContext = IntPtr.Zero;
        }

        #endregion

        #region Metodos Publicos

        /// <summary>
        /// Inicializa OpenGl
        /// </summary>
        /// <returns>True si se inicializo, sino false</returns>
        public bool Init(Control RenderTarget) 
        {            
            //Variables Locales
            int pixelFormat;
            Gdi.PIXELFORMATDESCRIPTOR pixelFormatDescriptor;
            

            //Paso de datos
            _renderTarget = RenderTarget;

            //Intentamos obtener el device context de la ventana
            DeviceContext = GetDC(_renderTarget.Handle);
            if (DeviceContext == IntPtr.Zero) 
            {
                //y mostramos un mensaje de error si no se pudo
                MessageBox.Show(_renderTarget, "No se pudo obtener el"
                                    + " Device Context para la ventana","Error"
                                    ,MessageBoxButtons.OK,MessageBoxIcon.Error);

                _renderTarget = null;

                return false;
            }         

            //Se llena el pixelformatdescriptor y hacemos que el programa
            //escoja un formato de pixeles adecuado
            pixelFormatDescriptor = llenarPixelFormatDescriptor();
            pixelFormat = Gdi.ChoosePixelFormat(DeviceContext, ref pixelFormatDescriptor);
            if (pixelFormat == 0) 
            {
                //Y chequiamos si se pudo o no
                MessageBox.Show(_renderTarget, "No se pudo escoger un"
                                    + " Formato de pixeles", "Error"
                                    ,MessageBoxButtons.OK,MessageBoxIcon.Error);

                ReleaseDC(_renderTarget.Handle, DeviceContext);

                DeviceContext = IntPtr.Zero;
                _renderTarget = null;

                return false;
            }

            //Ñe decimos al programa que use ese formato de pixeles en la ventana
            if (!Gdi._SetPixelFormat(DeviceContext, pixelFormat, ref pixelFormatDescriptor))
            {
                MessageBox.Show(_renderTarget, "No se pudo setear el"
                                    + " Formato de pixeles para la ventana", "Error"
                                    ,MessageBoxButtons.OK,MessageBoxIcon.Error);

                ReleaseDC(_renderTarget.Handle, DeviceContext);

                DeviceContext = IntPtr.Zero;
                _renderTarget = null;

                return false;
            }

            //Con el deveice context  creamos un render context para el programa
            RenderContext = Wgl.wglCreateContext(DeviceContext);
            if (RenderContext == IntPtr.Zero) 
            {
                MessageBox.Show(_renderTarget, "No se pudo obtener el"
                                    + " Render Context para la ventana", "Error"
                                    , MessageBoxButtons.OK, MessageBoxIcon.Error);

                ReleaseDC(_renderTarget.Handle, DeviceContext);

                DeviceContext = IntPtr.Zero;
                _renderTarget = null;

                return false;
            }

            //Acemos que el thread que llama al metodo use el render context
            //que creamos como su render context actual
            if (!Wgl.wglMakeCurrent(DeviceContext, RenderContext))
            {
                MessageBox.Show(_renderTarget, "No se pudo obtener el"
                                    + " Render Context para la ventana", "Error"
                                    , MessageBoxButtons.OK, MessageBoxIcon.Error);

                Wgl.wglDeleteContext(RenderContext);
                ReleaseDC(_renderTarget.Handle, DeviceContext);

                RenderContext = IntPtr.Zero;
                DeviceContext = IntPtr.Zero;
                _renderTarget = null;

                return false;
            }

            return true;
        }

        public bool Release()
        {            
            //Revisa si se ha llamado al metodo init correctamente antes de liberar
            //los recursos
            if (RenderContext == IntPtr.Zero || DeviceContext == IntPtr.Zero) 
            {
                MessageBox.Show("No esta inicializado");
                return false;
            }

            //Dejamos de hacer que el thread use nuestro rendercontext para dibujar
            if (!Wgl.wglMakeCurrent(IntPtr.Zero, IntPtr.Zero))
            {
                MessageBox.Show(_renderTarget, "No se pudo liberar al DC y al RC",
                    "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
                return false;
            }

            //Liberamos el Rendering Context
            if (!Wgl.wglDeleteContext(RenderContext)) 
            {
                MessageBox.Show(_renderTarget, "No se pudo liberar al RenderContext",
                    "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
                return false;
            }
            RenderContext = IntPtr.Zero;

            //Liberamos al Device Context
            if (!ReleaseDC(_renderTarget.Handle, DeviceContext)) 
            {
                MessageBox.Show(_renderTarget, "No se pudo liberar al Device Context",
                     "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
                return false;
            }
            DeviceContext = IntPtr.Zero;

            //y limpio la referencia a la ventana
            _renderTarget = null;
            
            return true;
        }

        #endregion

        #region Metodos Privados

        private Gdi.PIXELFORMATDESCRIPTOR llenarPixelFormatDescriptor() 
        {
            Gdi.PIXELFORMATDESCRIPTOR pixelFormat = new Gdi.PIXELFORMATDESCRIPTOR();

            pixelFormat.nSize = (short)Marshal.SizeOf(pixelFormat);
            pixelFormat.nVersion = 1; //En Windows siempre es 1

            pixelFormat.dwFlags = Gdi.PFD_DRAW_TO_WINDOW | Gdi.PFD_DOUBLEBUFFER | 
                Gdi.PFD_SUPPORT_OPENGL;

            //La otra opcion en pixel Type es el modo paleta que es muy antiguo
            pixelFormat.iPixelType = Gdi.PFD_TYPE_RGBA;    

            pixelFormat.cColorBits = ColorBits;
            pixelFormat.cDepthBits = DepthBits;
            pixelFormat.cStencilBits = 0;  //No lo necesitamos en esta oportunidad
            pixelFormat.cAuxBuffers = 0; //No es permitido en esta implementacion

            pixelFormat.bReserved = 0; //No necesitamos underlay o overlay planes
            pixelFormat.dwVisibleMask = 0; //No usamos Underlay planes

            #region Propiedades que no usamos
            pixelFormat.iLayerType = 0;
            pixelFormat.dwLayerMask = 0;
            pixelFormat.dwDamageMask = 0;

            pixelFormat.cRedBits = 0;
            pixelFormat.cGreenBits = 0;
            pixelFormat.cBlueBits = 0;
            pixelFormat.cAlphaBits = 0;

            pixelFormat.cAccumBits = 0;
            pixelFormat.cAccumBlueBits = 0;
            pixelFormat.cAccumGreenBits = 0;
            pixelFormat.cAccumRedBits = 0;
            pixelFormat.cAccumAlphaBits = 0;
            
            pixelFormat.cRedShift = 0;
            pixelFormat.cGreenShift = 0;
            pixelFormat.cBlueShift = 0;
            pixelFormat.cAlphaShift = 0;                        
            
            #endregion

            return pixelFormat;
        }

        #endregion
        
    }



Excuse the use of spanish comments, they were too many to translate. Ok, so In the form1 class I create an object of the Raster class, after the InitializeComponents() method has been called, I initialize some variables and call the Init(Control RenderTarget) method of the raster object giving it the panel(this instead of the SimpleOpenglControl InitializeContexts() Method). Then I force a change in the form size to call an event that will set the viewport and the ortho projection(this is called every time the window resizes). Finally in the Render method at the end I use the Gdi.SwapBuffers method giving it the DeviceContext from the raster object(Instead of the SimpleOpenGlControl SwapBuffers() method). Thanks to anybody who read all of this XD, any help is appreciated. [Edited by - crackers on February 19, 2008 10:00:15 AM]
Advertisement
Why are you doing this ?

SimpleOpenGLControl works just fine.

What should a panel improve `?
hehe, I love it how these Tao guys call it OpenGl
Sig: http://glhlib.sourceforge.net
an open source GLU replacement library. Much more modern than GLU.
float matrix[16], inverse_matrix[16];
glhLoadIdentityf2(matrix);
glhTranslatef2(matrix, 0.0, 0.0, 5.0);
glhRotateAboutXf2(matrix, angleInRadians);
glhScalef2(matrix, 1.0, 1.0, -1.0);
glhQuickInvertMatrixf2(matrix, inverse_matrix);
glUniformMatrix4fv(uniformLocation1, 1, FALSE, matrix);
glUniformMatrix4fv(uniformLocation2, 1, FALSE, inverse_matrix);
Quote:
Why are you doing this ?

SimpleOpenGLControl works just fine.

What should a panel improve `?


I don't know what the panel would improve but I was using it because the SimpleOpenGLControl was giving me buggy graphics, but now I found what the problem was, I wasn't calling the Render Method at all XD, now it works fine with both the SimpleOpenGlControl and my implementation, except that when I resize the window it looks like I get too far away from the image or it becomes too small.

Before Resizing: http://link.imgshare.us/2hjG4L

After Resizing : http://link.imgshare.us/2hjGGz

PS: I also wanted to create my own implementation to get more control over the context creation and because I want to learn more about how OpenGL works
@crackers: Make sure you reset the projection matrix on each resize event.

@V-man: That was an unfortunate design decision (or lack of design) when Tao was first conceived. Alas, it's too late to fix now, too many applications depend on it (the clean break was done on OpenTK - see sig).

[OpenTK: C# OpenGL 4.4, OpenGL ES 3.0 and OpenAL 1.1. Now with Linux/KMS support!]

I think I am doing that:
private void ResizeGLWindow(int Width, int Height)         {            Gl.glViewport(0, 0, Width, Height);                        Gl.glMatrixMode(Gl.GL_PROJECTION);                         Gl.glLoadIdentity();                        Gl.glOrtho(-200, 200, -200, 200, -2000, 2000);                         Gl.glMatrixMode(Gl.GL_MODELVIEW);        }protected override void OnSizeChanged(EventArgs e)        {            //I change the panel's size to match the new window's size            this.renderPanel.Width = (this.Width - Ancho - _separadorx);            this.renderPanel.Height = (this.Height - menu.Height - _separadory);            base.OnSizeChanged(e);            //I call the method that sets the viewport            ResizeGLWindow(this.renderPanel.Width, this.renderPanel.Height);        }

I'll try the OpenTK, thanks for the help

edit: Moving the code from ResizeGLWindow to the constructor gave me the problem right from the start, maybe the problem is in that method but I don't know what it is, my code in that method it's just like the book's code but the book's program works fine.
Thanks again

edit2: Yep the values from glOrtho were giving me troubles, although they do work in the book's example. The values that fixed it were:
Gl.glOrtho(-1, 1, -1, 1, -2000, 2000);
Thanks again for the help :D

PS:I just had one more question though. I started learning DirectX a few months ago and in some tutorials they said that you could loose control of the device and had to create a method to regain control of it, does that happens too in OpenGL?

[Edited by - crackers on February 19, 2008 10:42:53 AM]

This topic is closed to new replies.

Advertisement