using System; using System.ComponentModel; using System.Diagnostics; using System.Drawing; using System.Drawing.Imaging; using System.IO; using System.Runtime.InteropServices; using System.Windows.Forms; using Tao.OpenGl; using Tao.Platform.Windows; namespace Core { #region Class Documentation /// /// Lesson 15: Adding Textures To Outline Fonts. /// /// /// /// Original Author: Jeff Molofee (NeHe) /// http://nehe.gamedev.net/data/lessons/lesson.asp?lesson=15 /// /// /// C# Implementation: Randy Ridge /// http://www.taoframework.com /// /// #endregion Class Documentation public sealed class SuperShape : Form { static float m=1,n1=1,n2=1,n3=1; // --- Fields --- #region Private Static Fields private static IntPtr hDC; // Private GDI Device Context private static IntPtr hRC; // Permanent Rendering Context private static Form form; // Our Current Windows Form private static bool[] keys = new bool[256]; // Array Used For The Keyboard Routine private static bool active = true; // Window Active Flag, Set To True By Default private static bool fullscreen = true; // Fullscreen Flag, Set To Fullscreen Mode By Default private static bool done = false; // Bool Variable To Exit Main Loop private static int[] texture = new int[1]; // One Texture Map private static int fontbase; // Base Display List For The Font Set private static float rot=0,rotspeed=0; // Used To Rotate The Text #endregion Private Static Fields // --- Constructors & Destructors --- #region SuperShape /// /// Creates a new instance. /// public SuperShape() { 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 this.Activated += new EventHandler(this.Form_Activated); // On Activate Event Call Form_Activated this.Closing += new CancelEventHandler(this.Form_Closing); // On Closing Event Call Form_Closing this.Deactivate += new EventHandler(this.Form_Deactivate); // On Deactivate Event Call Form_Deactivate this.KeyDown += new KeyEventHandler(this.Form_KeyDown); // On KeyDown Event Call Form_KeyDown this.KeyUp += new KeyEventHandler(this.Form_KeyUp); // On KeyUp Event Call Form_KeyUp this.Resize += new EventHandler(this.Form_Resize); // On Resize Event Call Form_Resize } #endregion SuperShape // --- Entry Point --- #region Main(string[] commandLineArguments) /// /// The application's entry point. /// /// /// Any supplied command line arguments. /// [STAThread] public static void Main(string[] commandLineArguments) { // Ask The User Which Screen Mode They Prefer if(MessageBox.Show("Would You Like To Run In Fullscreen Mode?", "Start FullScreen?", MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.No) { fullscreen = false; // Windowed Mode } // Create Our OpenGL Window if(!CreateGLWindow("Paul Burkes super surfaces by Irrational Exuberance", 640, 480, 16, fullscreen)) { return; // Quit If Window Was Not Created } while(!done) { // Loop That Runs While done = false Application.DoEvents(); // Process Events // Draw The Scene. Watch For ESC Key And Quit Messages From DrawGLScene() if((active && (form != null) && !DrawGLScene()) || keys[(int) Keys.Escape]) { // Active? Was There A Quit Received? done = true; // ESC Or DrawGLScene Signalled A Quit } else { // Not Time To Quit, Update Screen Gdi.SwapBuffers(hDC); // Swap Buffers (float Buffering) } if(keys[(int) Keys.F1]) { // Is F1 Being Pressed? keys[(int) Keys.F1] = false; // If So Make Key false KillGLWindow(); // Kill Our Current Window fullscreen = !fullscreen; // Toggle Fullscreen / Windowed Mode // Recreate Our OpenGL Window if(!CreateGLWindow("NeHe's Texturemapped Outline Font Tutorial", 640, 480, 16, fullscreen)) { return; // Quit If Window Was Not Created } done = false; // We're Not Done Yet } const float fraction = 0.05f; if (keys[(int)Keys.P]) m+=fraction; if (keys[(int)Keys.M]) m-=fraction; if (keys[(int)Keys.O]) n1+=fraction; if (keys[(int)Keys.L]) n1-=fraction; if (keys[(int)Keys.I]) n2+=fraction; if (keys[(int)Keys.K]) n2-=fraction; if (keys[(int)Keys.U]) n3+=fraction; if (keys[(int)Keys.J]) n3-=fraction; // keys[(int)Keys.J]=keys[(int)Keys.U]= // keys[(int)Keys.K]=keys[(int)Keys.I]= // keys[(int)Keys.L]=keys[(int)Keys.O]= // keys[(int)Keys.M]=keys[(int)Keys.P]=false; float rotadd=0.01f; if(keys[(int) Keys.PageUp]) rotspeed+=rotadd; if(keys[(int) Keys.PageDown]) rotspeed-=rotadd; if(keys[(int) Keys.Home]) rotspeed=0f; if(keys[(int) Keys.End]) m=n1=n2=n3=1.0f; } // Shutdown KillGLWindow(); // Kill The Window return; // Exit The Program } #endregion Main(string[] commandLineArguments) // --- Private Static Methods --- #region BuildFont() /// /// Builds our bitmap font. /// private static void BuildFont() { Gdi.GLYPHMETRICSFLOAT[] gmf = new Gdi.GLYPHMETRICSFLOAT[256]; // Address Buffer For Font Storage IntPtr font; // Windows Font ID fontbase = Gl.glGenLists(256); // Storage For 256 Characters font = Gdi.CreateFont( // Create The Font -12, // Height Of Font 0, // Width Of Font 0, // Angle Of Escapement 0, // Orientation Angle Gdi.FW_BOLD, // Font Weight false, // Italic false, // Underline false, // Strikeout Gdi.SYMBOL_CHARSET, // Character Set Identifier Gdi.OUT_TT_PRECIS, // Output Precision Gdi.CLIP_DEFAULT_PRECIS, // Clipping Precision Gdi.ANTIALIASED_QUALITY, // Output Quality Gdi.FF_DONTCARE | Gdi.DEFAULT_PITCH, // Family And Pitch "Wingdings"); // Font Name Gdi.SelectObject(hDC, font); // Selects The Font We Created Wgl.wglUseFontOutlines( hDC, // Select The Current DC 0, // Starting Character 255, // Number Of Display Lists To Build fontbase, // Starting Display Lists 0.1f, // Deviation From The True Outlines 0.2f, // Font Thickness In The Z Direction Wgl.WGL_FONT_POLYGONS, // Use Polygons, Not Lines gmf); // Address Of Buffer To Recieve Data } #endregion BuildFont() #region bool CreateGLWindow(string title, int width, int height, int bits, bool fullscreenflag) /// /// Creates our OpenGL Window. /// /// /// The title to appear at the top of the window. /// /// /// The width of the GL window or fullscreen mode. /// /// /// The height of the GL window or fullscreen mode. /// /// /// The number of bits to use for color (8/16/24/32). /// /// /// Use fullscreen mode (true) or windowed mode (false). /// /// /// true on successful window creation, otherwise false. /// private static bool CreateGLWindow(string title, int width, int height, int bits, bool fullscreenflag) { int pixelFormat; // Holds The Results After Searching For A Match fullscreen = fullscreenflag; // Set The Global Fullscreen Flag form = null; // Null The Form GC.Collect(); // Request A Collection // This Forces A Swap Kernel.SetProcessWorkingSetSize(Process.GetCurrentProcess().Handle, -1, -1); if(fullscreen) { // Attempt Fullscreen Mode? Gdi.DEVMODE dmScreenSettings = new Gdi.DEVMODE(); // Device Mode // Size Of The Devmode Structure dmScreenSettings.dmSize = (short) Marshal.SizeOf(dmScreenSettings); dmScreenSettings.dmPelsWidth = width; // Selected Screen Width dmScreenSettings.dmPelsHeight = height; // Selected Screen Height dmScreenSettings.dmBitsPerPel = bits; // Selected Bits Per Pixel dmScreenSettings.dmFields = Gdi.DM_BITSPERPEL | Gdi.DM_PELSWIDTH | Gdi.DM_PELSHEIGHT; // Try To Set Selected Mode And Get Results. NOTE: CDS_FULLSCREEN Gets Rid Of Start Bar. if(User.ChangeDisplaySettings(ref dmScreenSettings, User.CDS_FULLSCREEN) != User.DISP_CHANGE_SUCCESSFUL) { // If The Mode Fails, Offer Two Options. Quit Or Use Windowed Mode. if(MessageBox.Show("The Requested Fullscreen Mode Is Not Supported By\nYour Video Card. Use Windowed Mode Instead?", "NeHe GL", MessageBoxButtons.YesNo, MessageBoxIcon.Exclamation) == DialogResult.Yes) { fullscreen = false; // Windowed Mode Selected. Fullscreen = false } else { // Pop up A Message Box Lessing User Know The Program Is Closing. MessageBox.Show("Program Will Now Close.", "ERROR", MessageBoxButtons.OK, MessageBoxIcon.Stop); return false; // Return false } } } form = new SuperShape(); // Create The Window if(fullscreen) { // Are We Still In Fullscreen Mode? form.FormBorderStyle = FormBorderStyle.None; // No Border Cursor.Hide(); // Hide Mouse Pointer } else { // If Windowed form.FormBorderStyle = FormBorderStyle.Sizable; // Sizable Cursor.Show(); // Show Mouse Pointer } form.Width = width; // Set Window Width form.Height = height; // Set Window Height form.Text = title; // Set Window Title 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 float Buffering pfd.iPixelType = (byte) Gdi.PFD_TYPE_RGBA; // Request An RGBA Format pfd.cColorBits = (byte) bits; // 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(form.Handle); // Attempt To Get A Device Context if(hDC == IntPtr.Zero) { // Did We Get A Device Context? KillGLWindow(); // Reset The Display MessageBox.Show("Can't Create A GL Device Context.", "ERROR", MessageBoxButtons.OK, MessageBoxIcon.Error); return false; } pixelFormat = Gdi.ChoosePixelFormat(hDC, ref pfd); // Attempt To Find An Appropriate Pixel Format if(pixelFormat == 0) { // Did Windows Find A Matching Pixel Format? KillGLWindow(); // Reset The Display MessageBox.Show("Can't Find A Suitable PixelFormat.", "ERROR", MessageBoxButtons.OK, MessageBoxIcon.Error); return false; } if(!Gdi.SetPixelFormat(hDC, pixelFormat, ref pfd)) { // Are We Able To Set The Pixel Format? KillGLWindow(); // Reset The Display MessageBox.Show("Can't Set The PixelFormat.", "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? KillGLWindow(); // Reset The Display MessageBox.Show("Can't Create A GL Rendering Context.", "ERROR", MessageBoxButtons.OK, MessageBoxIcon.Error); return false; } if(!Wgl.wglMakeCurrent(hDC, hRC)) { // Try To Activate The Rendering Context KillGLWindow(); // Reset The Display MessageBox.Show("Can't Activate The GL Rendering Context.", "ERROR", MessageBoxButtons.OK, MessageBoxIcon.Error); return false; } form.Show(); // Show The Window form.TopMost = true; // Topmost Window form.Focus(); // Focus The Window if(fullscreen) { // This Shouldn't Be Necessary, But Is Cursor.Hide(); } ReSizeGLScene(width, height); // Set Up Our Perspective GL Screen if(!InitGL()) { // Initialize Our Newly Created GL Window KillGLWindow(); // Reset The Display MessageBox.Show("Initialization Failed.", "ERROR", MessageBoxButtons.OK, MessageBoxIcon.Error); return false; } return true; // Success } #endregion bool CreateGLWindow(string title, int width, int height, int bits, bool fullscreenflag) #region bool DrawGLScene() /// /// Here's where we do all the drawing. /// /// /// true on successful drawing, otherwise false. /// private static bool DrawGLScene() { Gl.glClear(Gl.GL_COLOR_BUFFER_BIT | Gl.GL_DEPTH_BUFFER_BIT); // Clear the Screen and the Depth Buffer Gl.glMatrixMode(Gl.GL_MODELVIEW); // Modelview Matrix Gl.glLoadIdentity(); // reset the current modelview matrix AddLight(); Gl.glTranslatef(-1.5f,0.0f,-6.0f); // move 1.5 Units left and 6 Units into the screen Gl.glRotatef(rot,1,1,1); if (keys[(int)Keys.W]) Gl.glBegin(Gl.GL_LINES); else Gl.glBegin(Gl.GL_QUADS); DoCalc(40,40,m,n1,n2,n3); // DoQuad(); Gl.glEnd(); rot += rotspeed; // Increase The Rotation Variable return true; } #endregion bool DrawGLScene() static void DoQuad() { Gl.glColor3f(1.0f,0.5f,0.0f); // orange Gl.glVertex3f(1.0f,-1.0f,1.0f); // top right (bottom) Gl.glVertex3f(-1.0f,-1.0f,1.0f); // top left (bottom) Gl.glVertex3f(-1.0f,-1.0f,-1.0f); // bottom left (bottom) Gl.glVertex3f(1.0f,-1.0f,-1.0f); // bottom right (bottom) } //2D supershape Paul Burke static void Eval2D(float m,float n1,float n2,float n3,float phi,ref float x,ref float y){ double r; double t1,t2; double a=1,b=1; t1 = Math.Cos(m * phi / 4) / a; t1 = Math.Abs(t1); t1 = Math.Pow(t1,n2); t2 = Math.Sin(m * phi / 4) / b; t2 = Math.Abs(t2); t2 = Math.Pow(t2,n3); r = Math.Pow(t1+t2,1/n1); if (Math.Abs(r) == 0) { x = 0; y = 0; } else { r = 1 / r; x = (float)(r * Math.Cos(phi)); y = (float)(r * Math.Sin(phi)); } } //3D supershape Paul Burke static void Eval3D(float m,float n1,float n2,float n3,float phi,float theta,ref float x,ref float y,ref float z){ double r; double t1,t2; double a=1,b=1; Eval2D(m,n1,n2,n3,phi,ref x,ref y); t1 = Math.Cos(m * theta / 4) / a; t1 = Math.Abs(t1); t1 = Math.Pow(t1,n2); t2 = Math.Sin(m * theta / 4) / b; t2 = Math.Abs(t2); t2 = Math.Pow(t2,n3); r = Math.Pow(t1+t2,1/n1); if (Math.Abs(r) == 0) { x = 0; y = 0; z = 0; } else { r = 1 / r; x *= (float)(r * Math.Cos(theta)); y *= (float)(r * Math.Cos(theta)); z = (float) (r * Math.Sin(theta)); } } static void AddLight() { float[] LightAmbient= { 0.5f, 0.5f, 0.5f, 1.0f }; // Ambient Light Values ( NEW ) float[] LightDiffuse= { 1.0f, 1.0f, 1.0f, 1.0f }; // Diffuse Light Values ( NEW ) float[] LightPosition= { 0.0f, 0.0f, -6.0f, 1.0f }; // Light Position ( NEW ) Gl.glLightfv(Gl.GL_LIGHT1, Gl.GL_AMBIENT, LightAmbient); // Setup The Ambient Light Gl.glLightfv(Gl.GL_LIGHT1, Gl.GL_DIFFUSE, LightDiffuse); // Setup The Diffuse Light Gl.glLightfv(Gl.GL_LIGHT1, Gl.GL_POSITION,LightPosition); // Position The Light Gl.glEnable(Gl.GL_LIGHT1); // Enable Light One } static void DoCalc(float stepsx,float stepsy,float m,float n1,float n2,float n3) { float phi = -(float)Math.PI; float addPhi = (float)Math.PI*2 / stepsx; float theta; float addTheta = (float)Math.PI/stepsy; float x1=0,y1=0,z1=0; float x2=0,y2=0,z2=0; float x3=0,y3=0,z3=0; float x4=0,y4=0,z4=0; float scale=1; for (int i=0;i<=stepsx;i++) { theta = -(float)Math.PI/2; for (int j=0;j // create vectors float v1x=x1-x2; float v2x=x2-x3; float v1y=y1-y2; float v2y=y2-y3; float v1z=z1-z2; float v2z=z2-z3; // Get cross product of vectors float nx = (v1y * v2z) - (v1z * v2y); float ny = (v1z * v2x) - (v1x * v2z); float nz = (v1x * v2y) - (v1y * v2x); // Normalise final vector float vLen = (float)Math.Sqrt( (nx * nx) + (ny * ny) + (nz * nz) ); Gl.glNormal3f(nx/vLen, ny/vLen, nz/vLen); Gl.glVertex3f(x1*scale, y1*scale, z1*scale); Gl.glVertex3f(x2*scale, y2*scale, z2*scale); Gl.glVertex3f(x3*scale, y3*scale, z3*scale); Gl.glVertex3f(x4*scale, y4*scale, z4*scale); theta+=addTheta; } phi+=addPhi; } } #region glPrint(string text) /// /// Custom GL "print" routine. /// /// /// The text to print. /// private static void glPrint(string text) { if(text == null || text.Length == 0) { // If There's No Text return; // Do Nothing } Gl.glPushAttrib(Gl.GL_LIST_BIT); // Pushes The Display List Bits Gl.glListBase(fontbase); // Sets The Base Character to 0 // .NET: We can't draw text directly, it's a string! byte [] textbytes = new byte [text.Length]; for (int i = 0; i < text.Length; i++) textbytes[i] = (byte) text[i]; Gl.glCallLists(text.Length, Gl.GL_UNSIGNED_BYTE, textbytes); // Draws The Display List Text Gl.glPopAttrib(); // Pops The Display List Bits } #endregion glPrint(string text) #region bool InitGL() /// /// All setup for OpenGL goes here. /// /// /// true on successful initialization, otherwise false. /// private static bool InitGL() { /* if(!LoadGLTextures()) { // Jump To Texture Loading Routine return false; // If Texture Didn't Load Return False } */ BuildFont(); // Build The Font Gl.glShadeModel(Gl.GL_SMOOTH); // Enable Smooth Shading Gl.glClearColor(0, 0, 0.5f, 0.5f); // Black Background Gl.glClearDepth(1); // Depth Buffer Setup Gl.glEnable(Gl.GL_DEPTH_TEST); // Enables Depth Testing Gl.glDepthFunc(Gl.GL_LEQUAL); // The Type Of Depth Testing To Do Gl.glEnable(Gl.GL_LIGHT0); // Quick And Dirty Lighting (Assumes Light0 Is Set Up) Gl.glEnable(Gl.GL_LIGHTING); // Enable Lighting Gl.glHint(Gl.GL_PERSPECTIVE_CORRECTION_HINT, Gl.GL_NICEST); // Really Nice Perspective Calculations // Gl.glEnable(Gl.GL_TEXTURE_2D); // Enable Texture Mapping // Gl.glBindTexture(Gl.GL_TEXTURE_2D, texture[0]); // Select The Texture return true; } #endregion bool InitGL() #region KillFont() /// /// Delete the font list. /// private static void KillFont() { Gl.glDeleteLists(fontbase, 256); // Delete All 256 Characters } #endregion KillFont() #region KillGLWindow() /// /// Properly kill the window. /// private static void KillGLWindow() { if(fullscreen) { // Are We In Fullscreen Mode? User.ChangeDisplaySettings(IntPtr.Zero, 0); // If So, Switch Back To The Desktop Cursor.Show(); // Show Mouse Pointer } if(hRC != IntPtr.Zero) { // Do We Have A Rendering Context? 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.", "SHUTDOWN ERROR", MessageBoxButtons.OK, MessageBoxIcon.Error); } if(!Wgl.wglDeleteContext(hRC)) { // Are We Able To Delete The RC? MessageBox.Show("Release Rendering Context Failed.", "SHUTDOWN ERROR", MessageBoxButtons.OK, MessageBoxIcon.Error); } hRC = IntPtr.Zero; // Set RC To Null } if(hDC != IntPtr.Zero) { // Do We Have A Device Context? if(form != null && !form.IsDisposed) { // Do We Have A Window? if(form.Handle != IntPtr.Zero) { // Do We Have A Window Handle? if(!User.ReleaseDC(form.Handle, hDC)) { // Are We Able To Release The DC? MessageBox.Show("Release Device Context Failed.", "SHUTDOWN ERROR", MessageBoxButtons.OK, MessageBoxIcon.Error); } } } hDC = IntPtr.Zero; // Set DC To Null } if(form != null) { // Do We Have A Windows Form? form.Hide(); // Hide The Window form.Close(); // Close The Form form = null; // Set form To Null } KillFont(); } #endregion KillGLWindow() #region Bitmap LoadBMP(string fileName) /// /// Loads a bitmap image. /// /// /// The filename to load. /// /// /// The bitmap if it exists, otherwise null. /// private static Bitmap LoadBMP(string fileName) { if(fileName == null || fileName == string.Empty) { // Make Sure A Filename Was Given return null; // If Not Return Null } string fileName1 = string.Format("Data{0}{1}", // Look For Data\Filename Path.DirectorySeparatorChar, fileName); string fileName2 = string.Format("{0}{1}{0}{1}Data{1}{2}", // Look For ..\..\Data\Filename "..", Path.DirectorySeparatorChar, fileName); // Make Sure The File Exists In One Of The Usual Directories if(!File.Exists(fileName) && !File.Exists(fileName1) && !File.Exists(fileName2)) { return null; // If Not Return Null } if(File.Exists(fileName)) { // Does The File Exist Here? return new Bitmap(fileName); // Load The Bitmap } else if(File.Exists(fileName1)) { // Does The File Exist Here? return new Bitmap(fileName1); // Load The Bitmap } else if(File.Exists(fileName2)) { // Does The File Exist Here? return new Bitmap(fileName2); // Load The Bitmap } return null; // If Load Failed Return Null } #endregion Bitmap LoadBMP(string fileName) #region bool LoadGLTextures() /// /// Load bitmaps and convert to textures. /// /// /// true on success, otherwise false. /// private static bool LoadGLTextures() { bool status = false; // Status Indicator Bitmap[] textureImage = new Bitmap[1]; // Create Storage Space For The Texture textureImage[0] = LoadBMP(@"c:\tmp\x\Lights.bmp"); // Load The Bitmap // Check For Errors, If Bitmap's Not Found, Quit if(textureImage[0] != null) { status = true; // Set The Status To True Gl.glGenTextures(1, out texture[0]); // Create The Texture textureImage[0].RotateFlip(RotateFlipType.RotateNoneFlipY); // Flip The Bitmap Along The Y-Axis // Rectangle For Locking The Bitmap In Memory Rectangle rectangle = new Rectangle(0, 0, textureImage[0].Width, textureImage[0].Height); // Get The Bitmap's Pixel Data From The Locked Bitmap BitmapData bitmapData = textureImage[0].LockBits(rectangle, ImageLockMode.ReadOnly, PixelFormat.Format24bppRgb); // Typical Texture Generation Using Data From The Bitmap Gl.glBindTexture(Gl.GL_TEXTURE_2D, texture[0]); Glu.gluBuild2DMipmaps(Gl.GL_TEXTURE_2D, Gl.GL_RGB8, textureImage[0].Width, textureImage[0].Height, Gl.GL_RGB, Gl.GL_UNSIGNED_BYTE, bitmapData.Scan0); Gl.glTexParameteri(Gl.GL_TEXTURE_2D, Gl.GL_TEXTURE_MAG_FILTER, Gl.GL_LINEAR); Gl.glTexParameteri(Gl.GL_TEXTURE_2D, Gl.GL_TEXTURE_MIN_FILTER, Gl.GL_LINEAR_MIPMAP_NEAREST); Gl.glTexGeni(Gl.GL_S, Gl.GL_TEXTURE_GEN_MODE, Gl.GL_OBJECT_LINEAR); Gl.glTexGeni(Gl.GL_T, Gl.GL_TEXTURE_GEN_MODE, Gl.GL_OBJECT_LINEAR); Gl.glEnable(Gl.GL_TEXTURE_GEN_S); Gl.glEnable(Gl.GL_TEXTURE_GEN_T); if(textureImage[0] != null) { // If Texture Exists textureImage[0].UnlockBits(bitmapData); // Unlock The Pixel Data From Memory textureImage[0].Dispose(); // Dispose The Bitmap } } return status; // Return The Status } #endregion bool LoadGLTextures() #region ReSizeGLScene(int width, int height) /// /// Resizes and initializes the GL window. /// /// /// The new window width. /// /// /// The new window height. /// private static void ReSizeGLScene(int width, int height) { if(height == 0) { // Prevent A Divide By Zero... height = 1; // By Making Height Equal To One } Gl.glViewport(0, 0, width, height); // Reset The Current Viewport Gl.glMatrixMode(Gl.GL_PROJECTION); // Select The Projection Matrix Gl.glLoadIdentity(); // Reset The Projection Matrix Glu.gluPerspective(45, width / (float) height, 0.1, 100); // Calculate The Aspect Ratio Of The Window Gl.glMatrixMode(Gl.GL_MODELVIEW); // Select The Modelview Matrix Gl.glLoadIdentity(); // Reset The Modelview Matrix } #endregion ReSizeGLScene(int width, int height) // --- Private Instance Event Handlers --- #region Form_Activated /// /// Handles the form's activated event. /// /// /// The event sender. /// /// /// The event arguments. /// private void Form_Activated(object sender, EventArgs e) { active = true; // Program Is Active } #endregion Form_Activated #region Form_Closing(object sender, CancelEventArgs e) /// /// Handles the form's closing event. /// /// /// The event sender. /// /// /// The event arguments. /// private void Form_Closing(object sender, CancelEventArgs e) { done = true; // Send A Quit Message } #endregion Form_Closing(object sender, CancelEventArgs e) #region Form_Deactivate(object sender, EventArgs e) /// /// Handles the form's deactivate event. /// /// /// The event sender. /// /// /// The event arguments. /// private void Form_Deactivate(object sender, EventArgs e) { active = false; // Program Is No Longer Active } #endregion Form_Deactivate(object sender, EventArgs e) #region Form_KeyDown(object sender, KeyEventArgs e) /// /// Handles the form's key down event. /// /// /// The event sender. /// /// /// The event arguments. /// private void Form_KeyDown(object sender, KeyEventArgs e) { keys[e.KeyValue] = true; // Key Has Been Pressed, Mark It As true } #endregion Form_KeyDown(object sender, KeyEventArgs e) #region Form_KeyUp(object sender, KeyEventArgs e) /// /// Handles the form's key down event. /// /// /// The event sender. /// /// /// The event arguments. /// private void Form_KeyUp(object sender, KeyEventArgs e) { keys[e.KeyValue] = false; // Key Has Been Pressed, Mark It As true } #endregion Form_KeyUp(object sender, KeyEventArgs e) #region Form_Resize(object sender, EventArgs e) /// /// Handles the form's resize event. /// /// /// The event sender. /// /// /// The event arguments. /// private void Form_Resize(object sender, EventArgs e) { ReSizeGLScene(form.Width, form.Height); // Resize The OpenGL Window } #endregion Form_Resize(object sender, EventArgs e) } }