using System; using System.Windows.Forms; using System.Runtime.InteropServices; using System.IO; using System.Drawing; using sharp3d; // DllImport namespace sharpgl { /// /// Summary description for OpenGLForm. /// public class OpenGLForm : Form { public static float xrot; // X-axis rotation public static float yrot; // Y-axis rotation public static float zrot; // Z-axis rotation public static uint[] texture; // texture #region Member Variables /// /// Required designer variable. /// private System.ComponentModel.Container components = null; private static uint _hwnd = 0; private static uint _hDC = 0; private static uint _hRC = 0; private bool _appActive = true; public bool FullScreen { get; set; } public static bool Done { get; set; } #endregion #region Win32 Interop // Constant values were found in the "WinUser.h" header file. public const int WM_ACTIVATEAPP = 0x001C; public const int WA_ACTIVE = 1; public const int WA_CLICKACTIVE = 2; public const int CDS_FULLSCREEN = 0x00000004; // Flag for ChangeDisplaySettings public const int DISP_CHANGE_SUCCESSFUL = 0; // Return value for ChangeDisplaySettings // Constant values were found in the "WinGDI.h" header file. public const int CCHDEVICENAME = 32; // size of a device name string public const int CCHFORMNAME = 32; // size of a form name string public const int DM_BITSPERPEL = 0x40000; public const int DM_PELSWIDTH = 0x80000; public const int DM_PELSHEIGHT = 0x100000; public const int BITSPIXEL = 12; // number of bits per pixel public const uint PFD_DOUBLEBUFFER = 0x00000001; // PIXELFORMATDESCRIPTOR flag public const uint PFD_DRAW_TO_WINDOW = 0x00000004; // PIXELFORMATDESCRIPTOR flag public const uint PFD_SUPPORT_OPENGL = 0x00000020; // PIXELFORMATDESCRIPTOR flag public const uint PFD_TYPE_RGBA = 0; // pixel type public const uint PFD_MAIN_PLANE = 0; // layer type [StructLayout(LayoutKind.Sequential)] public struct PIXELFORMATDESCRIPTOR { public ushort nSize; public ushort nVersion; public uint dwFlags; public byte iPixelType; public byte cColorBits; public byte cRedBits; public byte cRedShift; public byte cGreenBits; public byte cGreenShift; public byte cBlueBits; public byte cBlueShift; public byte cAlphaBits; public byte cAlphaShift; public byte cAccumBits; public byte cAccumRedBits; public byte cAccumGreenBits; public byte cAccumBlueBits; public byte cAccumAlphaBits; public byte cDepthBits; public byte cStencilBits; public byte cAuxBuffers; public byte iLayerType; public byte bReserved; public uint dwLayerMask; public uint dwVisibleMask; public uint dwDamageMask; } // by marking the structure with CharSet.Auto, the structure will get marshaled as Unicode characters // on Unicode platforms, if not the name fields would always get marshaled as arrays of ANSI characters [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)] public class DEVMODE { [MarshalAs(UnmanagedType.ByValArray, SizeConst = CCHDEVICENAME)] public char[] dmDeviceName; public short dmSpecVersion; public short dmDriverVersion; public short dmSize; public short dmDriverExtra; public int dmFields; public DEVMODE_UNION u; public short dmColor; public short dmDuplex; public short dmYResolution; public short dmTTOption; public short dmCollate; [MarshalAs(UnmanagedType.ByValArray, SizeConst = CCHFORMNAME)] public char[] dmFormName; public short dmLogPixels; public int dmBitsPerPel; public int dmPelsWidth; public int dmPelsHeight; public int dmDisplayFlagsOrdmNup; // union of dmDisplayFlags and dmNup public int dmDisplayFrequency; public int dmICMMethod; public int dmICMIntent; public int dmMediaType; public int dmDitherType; public int dmReserved1; public int dmReserved2; public int dmPanningWidth; public int dmPanningHeight; } // modeling a union in C#, each possible struct data type starts at FieldOffset 0 [StructLayout(LayoutKind.Explicit)] public struct DEVMODE_UNION { [FieldOffset(0)] public short dmOrientation; [FieldOffset(2)] public short dmPaperSize; [FieldOffset(4)] public short dmPaperLength; [FieldOffset(6)] public short dmPaperWidth; [FieldOffset(8)] public short dmScale; [FieldOffset(10)] public short dmCopies; [FieldOffset(12)] public short dmDefaultSource; [FieldOffset(14)] public short dmPrintQuality; [FieldOffset(0)] public int dmPosition_x; [FieldOffset(4)] public int dmPosition_y; [FieldOffset(0)] public int dmDisplayOrientation; [FieldOffset(0)] public int dmDisplayFixedOutput; } #endregion #region DLLImport [DllImport("kernel32")] public static extern uint GetLastError(); [DllImport("user32")] public static extern uint GetDC(uint hwnd); [DllImport("user32")] public static extern int ReleaseDC(uint hWnd, uint hDC); [DllImport("user32", CharSet = CharSet.Auto)] public static extern int ChangeDisplaySettings([MarshalAs(UnmanagedType.LPStruct)] DEVMODE lpDevMode, uint dwflags); [DllImport("user32")] public static extern int ShowCursor(bool bShow); [DllImport("gdi32")] public static extern int ChoosePixelFormat(uint hdc, ref PIXELFORMATDESCRIPTOR ppfd); [DllImport("gdi32")] public static extern int SetPixelFormat(uint hdc, int iPixelFormat, ref PIXELFORMATDESCRIPTOR ppfd); [DllImport("gdi32")] public static extern int GetDeviceCaps(uint hdc, int nIndex); [DllImport("opengl32")] public static extern uint wglCreateContext(uint hdc); [DllImport("opengl32")] public static extern bool wglDeleteContext(uint hrc); [DllImport("opengl32")] public static extern uint wglSwapBuffers(uint hdc); [DllImport("opengl32")] public static extern bool wglMakeCurrent(uint hdc, uint hglrc); #endregion #region OpenGLSetup private bool SetupPixelFormat(ref uint hdc) { PIXELFORMATDESCRIPTOR pfd = new PIXELFORMATDESCRIPTOR(); ushort pfdSize = (ushort)Marshal.SizeOf(typeof(PIXELFORMATDESCRIPTOR)); // sizeof(PIXELFORMATDESCRIPTOR) pfd.nSize = pfdSize; // size of pfd pfd.nVersion = 1; // version number pfd.dwFlags = (PFD_SUPPORT_OPENGL | PFD_DRAW_TO_WINDOW | PFD_DOUBLEBUFFER); // flags pfd.iPixelType = (byte)PFD_TYPE_RGBA; // RGBA type pfd.cColorBits = (byte)GetDeviceCaps(hdc, BITSPIXEL); // 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; // accum bits ignored pfd.cAccumGreenBits = 0; pfd.cAccumBlueBits = 0; pfd.cAccumAlphaBits = 0; pfd.cDepthBits = 32; // 32-bit z-buffer pfd.cStencilBits = 0; // no stencil buffer pfd.cAuxBuffers = 0; // no auxiliary buffer pfd.iLayerType = (byte)PFD_MAIN_PLANE; // main layer pfd.bReserved = 0; // reserved pfd.dwLayerMask = 0; // layer masks ignored pfd.dwVisibleMask = 0; pfd.dwDamageMask = 0; int pixelformat = ChoosePixelFormat(hdc, ref pfd); if (pixelformat == 0) // Did Windows Find A Matching Pixel Format? { MessageBox.Show("Can't Find A Suitable PixelFormat.", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); return false; } if (SetPixelFormat(hdc, pixelformat, ref pfd) == 0) // Are We Able To Set The Pixel Format? { MessageBox.Show("Can't Set The PixelFormat.", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); return false; } return true; } private bool InitGL() { OpenGL.glShadeModel(OpenGL.GL_SMOOTH); OpenGL.glClearColor(0.0f, 0.0f, 0.0f, 0.5f); OpenGL.glClearDepth(1.0f); OpenGL.glEnable(OpenGL.GL_DEPTH_TEST); OpenGL.glDepthFunc(OpenGL.GL_LEQUAL); OpenGL.glHint(OpenGL.GL_PERSPECTIVE_CORRECTION_HINT, OpenGL.GL_NICEST); OpenGL.glEnable(OpenGL.GL_TEXTURE_2D); //OpenGL.glPolygonMode(OpenGL.GL_FRONT_AND_BACK, OpenGL.GL_LINE); return true; } public bool SetupRenderingContext() { if (!CreateGLWindow()) { return false; // initialization failed, quit } _hwnd = (uint)((this.Handle).ToInt32()); _hDC = GetDC(_hwnd); if (_hDC == 0) { MessageBox.Show("Can't Create A GL Device Context", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); return false; } // not doing the following wglSwapBuffers() on the DC will result in a failure to subsequently create the RC wglSwapBuffers(_hDC); if (!SetupPixelFormat(ref _hDC)) { return false; } // create the rendering context and make it current _hRC = wglCreateContext(_hDC); if (_hRC == 0) // Are We Able To Get A Rendering Context? { MessageBox.Show("Can't Create A GL Rendering Context.", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); return false; } if (!wglMakeCurrent(_hDC, _hRC)) // Try To Activate The Rendering Context { MessageBox.Show("Can't Activate The GL Rendering Context.", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); return false; } OpenGLForm_Resize(this, new EventArgs()); // Set up the perspective GL screen return InitGL(); // Initialize Our Newly Created GL Window } #endregion #region FormSetup private bool CreateGLWindow() { Resize += new EventHandler(OpenGLForm_Resize); if (FullScreen) { TopMost = true; WindowState = System.Windows.Forms.FormWindowState.Maximized; FormBorderStyle = System.Windows.Forms.FormBorderStyle.None; // The cursor is displayed only if the display count is greater than or equal to 0 do { } while (ShowCursor(false) >= 0); DEVMODE dmScreenSettings = new DEVMODE(); // Device Mode dmScreenSettings.dmSize = (short)Marshal.SizeOf(typeof(DEVMODE)); // Size Of The Devmode Structure dmScreenSettings.dmPelsWidth = 640; // Selected Screen Width dmScreenSettings.dmPelsHeight = 480; // Selected Screen Height dmScreenSettings.dmBitsPerPel = 16; // Selected Bits Per Pixel dmScreenSettings.dmFields = DM_PELSWIDTH | DM_PELSHEIGHT | DM_BITSPERPEL; // Try To Set Selected Mode And Get Results. NOTE: CDS_FULLSCREEN Gets Rid Of Start Bar. if (ChangeDisplaySettings(dmScreenSettings, CDS_FULLSCREEN) != 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?", "Error", MessageBoxButtons.YesNo, MessageBoxIcon.Error) == DialogResult.Yes) { FullScreen = false; // Windowed Mode Selected. Fullscreen = FALSE } else { // Pop Up A Message Box Letting User Know The Program Is Closing. MessageBox.Show("Program Will Now Close.", "Error", MessageBoxButtons.OK, MessageBoxIcon.Stop); return false; // setup failed, finished } } } if (!FullScreen) { TopMost = false; WindowState = System.Windows.Forms.FormWindowState.Normal; FormBorderStyle = System.Windows.Forms.FormBorderStyle.Sizable; // The cursor is displayed only if the display count is greater than or equal to 0 do { } while (ShowCursor(true) < 0); } return true; } #endregion #region Constructor/Destructor public OpenGLForm() { // // Required for Windows Form Designer support // InitializeComponent(); this.FormClosing += new FormClosingEventHandler(OpenGLForm_FormClosing); } void OpenGLForm_FormClosing(object sender, FormClosingEventArgs e) { Done = true; } /// /// Clean up any resources being used. /// protected override void Dispose(bool disposing) { if (disposing) { if (components != null) { components.Dispose(); } if (_hRC != 0) // Do We Have A Rendering Context? { if (!wglMakeCurrent(0, 0)) // Are We Able To Release The DC And RC Contexts? { MessageBox.Show("Release Of DC And RC Failed.", "Shutdown Error", MessageBoxButtons.OK, MessageBoxIcon.Information); } if (!wglDeleteContext(_hRC)) // Are We Able To Delete The RC? { MessageBox.Show("Release Rendering Context Failed.", "Shutdown Error", MessageBoxButtons.OK, MessageBoxIcon.Information); } } if (_hDC != 0 && ReleaseDC(_hwnd, _hDC) == 0) // Are We Able To Release The DC { MessageBox.Show("Release Device Context Failed.", "Shutdown Error", MessageBoxButtons.OK, MessageBoxIcon.Information); } } base.Dispose(disposing); } #endregion #region Windows Form Designer generated code /// /// Required method for Designer support - do not modify /// the contents of this method with the code editor. /// private void InitializeComponent() { this.SuspendLayout(); // // OpenGLForm // this.AutoScaleBaseSize = new System.Drawing.Size(5, 13); this.ClientSize = new System.Drawing.Size(632, 453); this.KeyPreview = true; this.Name = "OpenGLForm"; this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen; this.Text = "MainForm"; this.KeyUp += new System.Windows.Forms.KeyEventHandler(this.OpenGLForm_KeyUp); this.ResumeLayout(false); } #endregion #region Events protected override void WndProc(ref System.Windows.Forms.Message m) { // Listen for operating system messages. switch (m.Msg) { // The WM_ACTIVATEAPP message occurs when the application // becomes the active application or becomes inactive. case WM_ACTIVATEAPP: { // The WParam value identifies what is occurring. _appActive = ((int)m.WParam == WA_ACTIVE || (int)m.WParam == WA_CLICKACTIVE); // Invalidate to get new scene painted. Invalidate(); break; } default: { break; } } base.WndProc(ref m); } /*! This will stop the display from flickering on Paint event */ protected override void OnPaintBackground(PaintEventArgs e) { } protected override void OnPaint(PaintEventArgs e) { if (_appActive) { Draw(); wglSwapBuffers(_hDC); Invalidate(); } } private void OpenGLForm_KeyUp(object sender, System.Windows.Forms.KeyEventArgs e) { switch (e.KeyCode) { case Keys.Escape: { Close(); Done = true; break; } case Keys.F1: { if (FullScreen) // Are We In Fullscreen Mode? { ChangeDisplaySettings(null, 0); // If So Switch Back To The Desktop } FullScreen = !FullScreen; Done = false; Close(); // raise Close event to kill the current form, the form will get re-created in Main break; } default: { break; } } } private void OpenGLForm_Resize(object sender, EventArgs e) // Resize And Initialize The GL Window { int width = ClientRectangle.Width; int height = ClientRectangle.Height; if (height == 0) // Prevent A Divide By Zero By { height = 1; // Making Height Equal One } OpenGL.glViewport(0, 0, width, height); // Reset The Current Viewport OpenGL.glMatrixMode(OpenGL.GL_PROJECTION); // Select The Projection Matrix OpenGL.glLoadIdentity(); // Reset The Projection Matrix // Calculate The Aspect Ratio Of The Window OpenGLU.gluPerspective(45.0f, (double)width / (double)height, 0.1f, 100.0f); OpenGL.glMatrixMode(OpenGL.GL_MODELVIEW); // Select The Modelview Matrix OpenGL.glLoadIdentity(); // Reset The Modelview Matrix } #endregion public static MDLFile model = null; /// /// The main entry point for the application. /// [STAThread] static void Main() { bool fullScreen = false; texture = new uint[1]; // storage for texture while (!Done) { OpenGLForm form = new OpenGLForm(); // create the form form.FullScreen = fullScreen; // set the user display property option if (!form.SetupRenderingContext()) // setup form and OpenGL { break; // initialization failed, quit } else { model = new MDLFile("../../Models/Footman.mdl"); model.Parse(); } Application.Run(form); if (OpenGLForm.Done) // Was There A Quit Received? { break; } fullScreen = form.FullScreen; // switching between full screen and windowed, persist full screen option between forms } } public static void GenerateTexture(Texture texture) { Bitmap image = new Bitmap(texture.Image); System.Drawing.Imaging.BitmapData bitmapdata; Rectangle rect = new Rectangle(0, 0, image.Width, image.Height); bitmapdata = image.LockBits(rect, System.Drawing.Imaging.ImageLockMode.ReadOnly, System.Drawing.Imaging.PixelFormat.Format24bppRgb); uint index = 0; OpenGL.glGenTextures(1, out index); texture.TextureName = (int)index; //uint error = OpenGL.glGetError(); OpenGL.glBindTexture(OpenGL.GL_TEXTURE_2D, index); OpenGL.glTexImage2D(OpenGL.GL_TEXTURE_2D, 0, (int)OpenGL.GL_RGB8, (uint)image.Width, (uint)image.Height, 0, OpenGLExt.GL_BGR_EXT, OpenGL.GL_UNSIGNED_BYTE, bitmapdata.Scan0); OpenGL.glTexParameteri(OpenGL.GL_TEXTURE_2D, OpenGL.GL_TEXTURE_MIN_FILTER, (int)OpenGL.GL_LINEAR); OpenGL.glTexParameteri(OpenGL.GL_TEXTURE_2D, OpenGL.GL_TEXTURE_MAG_FILTER, (int)OpenGL.GL_LINEAR); image.UnlockBits(bitmapdata); image.Dispose(); } int time = 0; public bool Draw() { OpenGL.glClear(OpenGL.GL_COLOR_BUFFER_BIT | OpenGL.GL_DEPTH_BUFFER_BIT); OpenGL.glMatrixMode(OpenGL.GL_MODELVIEW); OpenGL.glLoadIdentity(); OpenGL.glTranslatef(0.0f, -12.0f, -50.0f); //OpenGL.glTranslatef(0.0f, 0.0f, -5.0f); OpenGL.glRotatef(-90.0f, 1.0f, 0.0f, 0.0f); //xrot += 0.3f; //OpenGL.glRotatef(-90.0f + yrot, 0.0f, 1.0f, 0.0f); //yrot -= .04f; OpenGL.glRotatef(-90.0f + zrot, 0.0f, 0.0f, 1.0f); zrot += 0.04f; //OpenGL.glRotatef(90f, 1.0f, 0.0f, 0.0f); OpenGL.glScalef(0.3f, 0.3f, 0.3f); uint error = OpenGL.glGetError(); time++; foreach (Shape shape in model.Shapes) { // TODO: manage multiple layers Material material = model.Materials[shape.MaterialId]; int textureId = material.Layers[0].TextureId; if (string.IsNullOrEmpty(model.Textures[textureId].Image) && material.Layers.Count > 1) { textureId = material.Layers[1].TextureId; } int textureName = 1; textureName = model.Textures[textureId].TextureName; OpenGL.glBindTexture(OpenGL.GL_TEXTURE_2D, (uint)textureName); //error = OpenGL.glGetError(); OpenGL.glBegin(OpenGL.GL_TRIANGLES); foreach (Triangle triangle in shape.Triangles) { if (triangle != null) { Vertex v1 = shape.Vertices[triangle.Vertices[0]]; Vertex v2 = shape.Vertices[triangle.Vertices[1]]; Vertex v3 = shape.Vertices[triangle.Vertices[2]]; TextureVertex tv1 = shape.TextureVertices[triangle.Vertices[0]]; TextureVertex tv2 = shape.TextureVertices[triangle.Vertices[1]]; TextureVertex tv3 = shape.TextureVertices[triangle.Vertices[2]]; OpenGL.glTexCoord2f(tv1.x, tv1.y); OpenGL.glVertex3f(v1.x, v1.y, v1.z); OpenGL.glTexCoord2f(tv2.x, tv2.y); OpenGL.glVertex3f(v2.x, v2.y, v2.z); OpenGL.glTexCoord2f(tv3.x, tv3.y); OpenGL.glVertex3f(v3.x, v3.y, v3.z); } } OpenGL.glEnd(); //break; } //glDraw(); return true; } public void glDraw() { OpenGL.glClear(OpenGL.GL_COLOR_BUFFER_BIT | OpenGL.GL_DEPTH_BUFFER_BIT); OpenGL.glMatrixMode(OpenGL.GL_MODELVIEW); OpenGL.glLoadIdentity(); OpenGL.glTranslatef(0.0f, 0.0f, -5.0f); OpenGL.glRotatef(xrot, 1.0f, 0.0f, 0.0f); xrot += 0.3f; OpenGL.glRotatef(yrot, 0.0f, 1.0f, 0.0f); yrot += 0.2f; OpenGL.glRotatef(zrot, 0.0f, 0.0f, 1.0f); zrot += 0.4f; OpenGL.glBegin(OpenGL.GL_QUADS); // Front Face OpenGL.glTexCoord2f(1.0f, 1.0f); // top right of texture OpenGL.glVertex3f(1.0f, 1.0f, 1.0f); // top right of quad OpenGL.glTexCoord2f(0.0f, 1.0f); // top left of texture OpenGL.glVertex3f(-1.0f, 1.0f, 1.0f); // top left of quad OpenGL.glTexCoord2f(0.0f, 0.0f); // bottom left of texture OpenGL.glVertex3f(-1.0f, -1.0f, 1.0f); // bottom left of quad OpenGL.glTexCoord2f(1.0f, 0.0f); // bottom right of texture OpenGL.glVertex3f(1.0f, -1.0f, 1.0f); // bottom right of quad // Back Face OpenGL.glTexCoord2f(1.0f, 1.0f); // top right of texture OpenGL.glVertex3f(-1.0f, 1.0f, -1.0f); // top right of quad OpenGL.glTexCoord2f(0.0f, 1.0f); // top left of texture OpenGL.glVertex3f(1.0f, 1.0f, -1.0f); // top left of quad OpenGL.glTexCoord2f(0.0f, 0.0f); // bottom left of texture OpenGL.glVertex3f(1.0f, -1.0f, -1.0f); // bottom left of quad OpenGL.glTexCoord2f(1.0f, 0.0f); // bottom right of texture OpenGL.glVertex3f(-1.0f, -1.0f, -1.0f); // bottom right of quad // Top Face OpenGL.glTexCoord2f(1.0f, 1.0f); // top right of texture OpenGL.glVertex3f(1.0f, 1.0f, -1.0f); // top right of quad OpenGL.glTexCoord2f(0.0f, 1.0f); // top left of texture OpenGL.glVertex3f(-1.0f, 1.0f, -1.0f); // top left of quad OpenGL.glTexCoord2f(0.0f, 0.0f); // bottom left of texture OpenGL.glVertex3f(-1.0f, 1.0f, 1.0f); // bottom left of quad OpenGL.glTexCoord2f(1.0f, 0.0f); // bottom right of texture OpenGL.glVertex3f(1.0f, 1.0f, 1.0f); // bottom right of quad // Bottom Face OpenGL.glTexCoord2f(1.0f, 1.0f); // top right of texture OpenGL.glVertex3f(1.0f, -1.0f, 1.0f); // top right of quad OpenGL.glTexCoord2f(0.0f, 1.0f); // top left of texture OpenGL.glVertex3f(-1.0f, -1.0f, 1.0f); // top left of quad OpenGL.glTexCoord2f(0.0f, 0.0f); // bottom left of texture OpenGL.glVertex3f(-1.0f, -1.0f, -1.0f); // bottom left of quad OpenGL.glTexCoord2f(1.0f, 0.0f); // bottom right of texture OpenGL.glVertex3f(1.0f, -1.0f, -1.0f); // bottom right of quad // Right Face OpenGL.glTexCoord2f(1.0f, 1.0f); // top right of texture OpenGL.glVertex3f(1.0f, 1.0f, -1.0f); // top right of quad OpenGL.glTexCoord2f(0.0f, 1.0f); // top left of texture OpenGL.glVertex3f(1.0f, 1.0f, 1.0f); // top left of quad OpenGL.glTexCoord2f(0.0f, 0.0f); // bottom left of texture OpenGL.glVertex3f(1.0f, -1.0f, 1.0f); // bottom left of quad OpenGL.glTexCoord2f(1.0f, 0.0f); // bottom right of texture OpenGL.glVertex3f(1.0f, -1.0f, -1.0f); // bottom right of quad // Left Face OpenGL.glTexCoord2f(1.0f, 1.0f); // top right of texture OpenGL.glVertex3f(-1.0f, 1.0f, 1.0f); // top right of quad OpenGL.glTexCoord2f(0.0f, 1.0f); // top left of texture OpenGL.glVertex3f(-1.0f, 1.0f, -1.0f); // top left of quad OpenGL.glTexCoord2f(0.0f, 0.0f); // bottom left of texture OpenGL.glVertex3f(-1.0f, -1.0f, -1.0f); // bottom left of quad OpenGL.glTexCoord2f(1.0f, 0.0f); // bottom right of texture OpenGL.glVertex3f(-1.0f, -1.0f, 1.0f); // bottom right of quad OpenGL.glEnd(); } } }