#region --- License ---
/* Licensed under the MIT/X11 license.
 * Copyright (c) 2006-2008 the OpenTK Team.
 * This notice may not be removed from any source distribution.
 * See license.txt for licensing details.
 */
#endregion

// TODO: Find paint program that can properly export 8/16-bit Textures and make sure they are loaded correctly.

using System;
using System.Diagnostics;
using System.Drawing;
using System.Drawing.Imaging;

using OpenTK;
using OpenTK.Graphics;
using OpenTK.Graphics.OpenGL;

namespace Examples.TextureLoaders
{
    class ImageGDI
    {

        public static void LoadFromDisk( string filename, out uint texturehandle, out TextureTarget dimension )
        {
            dimension = (TextureTarget) 0;
            texturehandle = TextureLoaderParameters.OpenGLDefaultTexture;
            ErrorCode GLError = ErrorCode.NoError;

            Bitmap CurrentBitmap = null;

            try // Exceptions will be thrown if any Problem occurs while working on the file. 
            {
                CurrentBitmap = new Bitmap( filename );
                if ( TextureLoaderParameters.FlipImages )
                    CurrentBitmap.RotateFlip( RotateFlipType.RotateNoneFlipY );

                if ( CurrentBitmap.Height > 1 )
                    dimension = TextureTarget.Texture2D;
                else
                    dimension = TextureTarget.Texture1D;

                GL.GenTextures( 1, out texturehandle );
                GL.BindTexture( dimension, texturehandle );

                #region Load Texture
                OpenTK.Graphics.OpenGL.PixelInternalFormat pif;
                OpenTK.Graphics.OpenGL.PixelFormat pf;
                OpenTK.Graphics.OpenGL.PixelType pt;

                if (TextureLoaderParameters.Verbose)
                   Trace.WriteLine( "File: " + filename + " Format: " + CurrentBitmap.PixelFormat );

                switch ( CurrentBitmap.PixelFormat )
                {
                case System.Drawing.Imaging.PixelFormat.Format8bppIndexed: // misses glColorTable setup
                    pif = OpenTK.Graphics.OpenGL.PixelInternalFormat.Rgb8;
                    pf = OpenTK.Graphics.OpenGL.PixelFormat.ColorIndex;
                    pt = OpenTK.Graphics.OpenGL.PixelType.Bitmap;
                    break;
                case System.Drawing.Imaging.PixelFormat.Format16bppArgb1555:
                case System.Drawing.Imaging.PixelFormat.Format16bppRgb555: // does not work
                    pif = OpenTK.Graphics.OpenGL.PixelInternalFormat.Rgb5A1;
                    pf = OpenTK.Graphics.OpenGL.PixelFormat.Bgr;
                    pt = OpenTK.Graphics.OpenGL.PixelType.UnsignedShort5551Ext;
                    break;
              /*  case System.Drawing.Imaging.PixelFormat.Format16bppRgb565:
                    pif = OpenTK.Graphics.OpenGL.PixelInternalFormat.R5G6B5IccSgix;
                    pf = OpenTK.Graphics.OpenGL.PixelFormat.R5G6B5IccSgix;
                    pt = OpenTK.Graphics.OpenGL.PixelType.UnsignedByte;
                    break;
*/
                case System.Drawing.Imaging.PixelFormat.Format24bppRgb: // works
                    pif = OpenTK.Graphics.OpenGL.PixelInternalFormat.Rgb8;
                    pf = OpenTK.Graphics.OpenGL.PixelFormat.Bgr;
                    pt = OpenTK.Graphics.OpenGL.PixelType.UnsignedByte;
                    break;
                case System.Drawing.Imaging.PixelFormat.Format32bppRgb: // has alpha too? wtf?
                case System.Drawing.Imaging.PixelFormat.Canonical:
                case System.Drawing.Imaging.PixelFormat.Format32bppArgb: // works
                    pif = OpenTK.Graphics.OpenGL.PixelInternalFormat.Rgba;
                    pf = OpenTK.Graphics.OpenGL.PixelFormat.Bgra;
                    pt = OpenTK.Graphics.OpenGL.PixelType.UnsignedByte;
                    break;
                default:
                    throw new ArgumentException( "ERROR: Unsupported Pixel Format " + CurrentBitmap.PixelFormat );
                }

                BitmapData Data = CurrentBitmap.LockBits( new System.Drawing.Rectangle( 0, 0, CurrentBitmap.Width, CurrentBitmap.Height ), ImageLockMode.ReadOnly, CurrentBitmap.PixelFormat );

                if ( Data.Height > 1 )
                { // image is 2D
                    if (TextureLoaderParameters.BuildMipmapsForUncompressed)
                    {
                        throw new Exception("Cannot build mipmaps, Glu is deprecated.");
                      //  Glu.Build2DMipmap(dimension, (int)pif, Data.Width, Data.Height, pf, pt, Data.Scan0);
                    }
                    else
                        GL.TexImage2D(dimension, 0, pif, Data.Width, Data.Height, TextureLoaderParameters.Border, pf, pt, Data.Scan0);
                } else
                { // image is 1D
                    if (TextureLoaderParameters.BuildMipmapsForUncompressed)
                    {
                        throw new Exception("Cannot build mipmaps, Glu is deprecated.");
                      //  Glu.Build1DMipmap(dimension, (int)pif, Data.Width, pf, pt, Data.Scan0);
                    }
                    else
                        GL.TexImage1D(dimension, 0, pif, Data.Width, TextureLoaderParameters.Border, pf, pt, Data.Scan0);
                }

                GL.Finish( );
                GLError = GL.GetError( );
                if ( GLError != ErrorCode.NoError )
                {
                    throw new ArgumentException( "Error building TexImage. GL Error: " + GLError );
                }

                CurrentBitmap.UnlockBits( Data );
                #endregion Load Texture

                #region Set Texture Parameters
                GL.TexParameter( dimension, TextureParameterName.TextureMinFilter, (int) TextureLoaderParameters.MinificationFilter );
                GL.TexParameter( dimension, TextureParameterName.TextureMagFilter, (int) TextureLoaderParameters.MagnificationFilter );

                GL.TexParameter( dimension, TextureParameterName.TextureWrapS, (int) TextureLoaderParameters.WrapModeS );
                GL.TexParameter( dimension, TextureParameterName.TextureWrapT, (int) TextureLoaderParameters.WrapModeT );

                GL.TexEnv( TextureEnvTarget.TextureEnv, TextureEnvParameter.TextureEnvMode, (int) TextureLoaderParameters.EnvMode );

                GLError = GL.GetError( );
                if ( GLError != ErrorCode.NoError )
                {
                    throw new ArgumentException( "Error setting Texture Parameters. GL Error: " + GLError );
                }
                #endregion Set Texture Parameters

                return; // success
            } catch ( Exception e )
            {
                dimension = (TextureTarget) 0;
                texturehandle = TextureLoaderParameters.OpenGLDefaultTexture;
                throw new ArgumentException( "Texture Loading Error: Failed to read file " + filename + ".\n" + e );
                // return; // failure
            } finally
            {
                CurrentBitmap = null;
            }
        }

    }
}