/// <summary> /// Makes this panel's OpenGL context current</summary> protected void SetCurrentContext() { if (!Wgl.wglMakeCurrent(m_hdc, m_hglrc)) { Util3D.ReportErrors(); throw new InvalidOperationException("Can't make this panel's GL context to be current"); } }
/// <summary> /// Ends drawing the canvas contents</summary> protected override void EndPaint() { if (m_isPicking) { Util3D.DrawHatchedFrame(Size, FirstMousePoint, CurrentMousePoint, Color.Black); } base.EndPaint(); }
/// <summary> /// Begins painting</summary> /// <exception cref="InvalidOperationException">Can't make this panel's GL context to be current</exception> protected virtual void BeginPaint() { StartGlIfNecessary(); if (!Wgl.wglMakeCurrent(m_hdc, m_hglrc)) { Util3D.ReportErrors(); throw new InvalidOperationException("Can't make this panel's GL context to be current"); } }
/// <summary> /// Draws a 3D arrow from point 1 to point 2 using an OpenGL display list for greatly improved /// performance. This method must not be called in between Gl.glNewList and Gl.glEndList.</summary> /// <param name="p1">Point 1</param> /// <param name="p2">Point 2</param> /// <param name="coneSize">Arrow head base diameter</param> public static void DrawArrowDisplayList(Vec3F p1, Vec3F p2, float coneSize) { Gl.glBegin(Gl.GL_LINES); Gl.glVertex3f(p1.X, p1.Y, p1.Z); Gl.glVertex3f(p2.X, p2.Y, p2.Z); Gl.glEnd(); Gl.glPushMatrix(); Gl.glTranslatef(p2.X, p2.Y, p2.Z); Gl.glPushMatrix(); Util3D.glMultMatrixf(LookAtMatrix(p2 - p1)); DrawConeDisplayList(coneSize, coneSize * 2, RenderStyle.Solid); Gl.glPopMatrix(); Gl.glPopMatrix(); Util3D.RenderStats.VertexCount += 2; }
/// <summary> /// Destroys all texture bindings for the given context</summary> /// <param name="contextId">Context ID of textures to destroy</param> public void DestroyTextures(object contextId) { TextureContext texCollection = FindContext(contextId); if (texCollection != null) { if (texCollection.Names.Count > 0) { int[] texs = new int[texCollection.Names.Count]; texCollection.Names.CopyTo(texs, 0); Gl.glDeleteTextures(texs.Length, texs); Util3D.ReportErrors(); } m_texCollections.Remove(texCollection); } }
/// <summary> /// Initializes an OpenGL context with the associated Win32 device context</summary> /// <param name="hdc">HDC from the window to which the new OpenGL context is bound</param> /// <param name="hglrc">Handle to the new OpenGL context</param> public static void InitOpenGl(IntPtr hdc, out IntPtr hglrc) { Gdi.PIXELFORMATDESCRIPTOR pfd = new Gdi.PIXELFORMATDESCRIPTOR(); PopulatePixelFormatDescriptor(ref pfd); // Attempt To Find An Appropriate Pixel Format int pixelFormat = Gdi.ChoosePixelFormat(hdc, ref pfd); if (pixelFormat == 0) { throw new InvalidOperationException("Can't find a suitable PixelFormat"); } // Attempt To Set The Pixel Format? if (!Gdi.SetPixelFormat(hdc, pixelFormat, ref pfd)) { throw new InvalidOperationException("Can't set the PixelFormat"); } // Attempt To Get The Rendering Context hglrc = Wgl.wglCreateContext(hdc); if (hglrc == IntPtr.Zero) { throw new InvalidOperationException("Can't create GL rendering context"); } if (s_sharedHglrc == IntPtr.Zero) { s_sharedHglrc = hglrc; } else { // We don't throw an exception on failure because the caller may be on another thread or is // using a different pixel format. Wgl.wglShareLists(s_sharedHglrc, hglrc); } if (!Wgl.wglMakeCurrent(hdc, hglrc)) { throw new InvalidOperationException("Can't make the OpenGL rendering context to be the current context."); } // Load all extensions for mainline rendering if (!s_initialized) { LoadAllExtensions(); s_initialized = true; } // Init fonts Gdi.SelectObject(hdc, SystemFonts.DefaultFont.ToHfont()); foreach (IntSet.Range range in s_fontMap.Ranges) { int baseDisplayListId = range.PreviousItemsCount + TEXT_DISPLAY_LIST_BASE; if (!wglUseFontBitmaps(hdc, range.Min, range.Count, (uint)baseDisplayListId)) { throw new InvalidOperationException("Font bitmaps were unable to be created."); } } s_fontMap.Lock(); Util3D.ReportErrors(); }
/// <summary> /// Loads a compressed texture using a call to glCompressedTexImage2DARB() as CUBE_MAP</summary> /// <param name="image">The Image</param> /// <param name="levels">Mipmap levels</param> private unsafe void CompressedTextureLoadPixelDataCUBEMAP(Image image, int levels) { IntPtr glCompressedTexImage2DARB = Gl.GetFunctionPointerForExtensionMethod("glCompressedTexImage2DARB"); if (glCompressedTexImage2DARB == IntPtr.Zero) { return; } int nBlockSize; if (image.OpenGlPixelFormat == Gl.GL_COMPRESSED_RGBA_S3TC_DXT1_EXT) { nBlockSize = 8; } else { nBlockSize = 16; } int offset = 0; // Load the mip-map levels for (int face = 0; face < 6; face++) { int nWidth = image.Width; int nHeight = image.Height; for (int i = 0; i < levels; ++i) { if (nWidth == 0) { nWidth = 1; } if (nHeight == 0) { nHeight = 1; } // nSize = ((nWidth + 3) / 4) * ((nHeight + 3) / 4) * nBlockSize; int nSize = ((nWidth + 3) >> 2) * ((nHeight + 3) >> 2) * nBlockSize; byte[] pixel = new byte[nSize]; for (int o = offset, j = 0; o < offset + nSize; o++, j++) { pixel[j] = image.Pixels[o]; } Gl.glCompressedTexImage2DARB( Gl.GL_TEXTURE_CUBE_MAP_POSITIVE_X + face, i, image.OpenGlPixelFormat, nWidth, nHeight, 0, nSize, pixel); offset += nSize; // Half the image size for the next mip-map level... nWidth = (nWidth >> 1); nHeight = (nHeight >> 1); } } Util3D.ReportErrors(); }
private unsafe void CompressedTextureLoadPixelData(Image image, int levels) { IntPtr glCompressedTexImage2DARB = Gl.GetFunctionPointerForExtensionMethod("glCompressedTexImage2DARB"); if (glCompressedTexImage2DARB == IntPtr.Zero) { return; } int nBlockSize; if (image.OpenGlPixelFormat == Gl.GL_COMPRESSED_RGBA_S3TC_DXT1_EXT) { nBlockSize = 8; } else { nBlockSize = 16; } int nWidth = image.Width; int nHeight = image.Height; int nSize; int nOffset = 0; // Load the mip-map levels fixed(byte *pixels = image.Pixels) { for (int i = 0; i < levels; ++i) { if (nWidth == 0) { nWidth = 1; } if (nHeight == 0) { nHeight = 1; } nSize = ((nWidth + 3) / 4) * ((nHeight + 3) / 4) * nBlockSize; Gl.glCompressedTexImage2DARB( Gl.GL_TEXTURE_2D, i, image.OpenGlPixelFormat, nWidth, nHeight, 0, nSize, new IntPtr(pixels + nOffset)); nOffset += nSize; // Half the image size for the next mip-map level... nWidth = (nWidth / 2); nHeight = (nHeight / 2); } } Util3D.ReportErrors(); }
private int TryCreateOpenGlTextureFromImage(Image image, TextureInfo textureInfo) { textureInfo.Format = image.OpenGlPixelFormat; textureInfo.Width = image.Width; textureInfo.Height = image.Height; textureInfo.Components = image.ElementsPerPixel; // Relax pixel data alignment restrictions down from 4 to 1 Gl.glPixelStorei(Gl.GL_UNPACK_ALIGNMENT, 1); int textureName; Gl.glGenTextures(1, out textureName); if (image.IsCubeMap) { Gl.glEnable(Gl.GL_TEXTURE_CUBE_MAP); Gl.glBindTexture(Gl.GL_TEXTURE_CUBE_MAP, textureName); // Initialize bound texture state Gl.glTexParameteri(Gl.GL_TEXTURE_CUBE_MAP, Gl.GL_TEXTURE_WRAP_R, Gl.GL_CLAMP_TO_EDGE); Gl.glTexParameteri(Gl.GL_TEXTURE_CUBE_MAP, Gl.GL_TEXTURE_WRAP_S, Gl.GL_CLAMP_TO_EDGE); Gl.glTexParameteri(Gl.GL_TEXTURE_CUBE_MAP, Gl.GL_TEXTURE_WRAP_T, Gl.GL_CLAMP_TO_EDGE); Gl.glTexParameteri(Gl.GL_TEXTURE_CUBE_MAP, Gl.GL_TEXTURE_MIN_FILTER, Gl.GL_LINEAR_MIPMAP_LINEAR); Gl.glTexParameteri(Gl.GL_TEXTURE_CUBE_MAP, Gl.GL_TEXTURE_MAX_LEVEL, image.Levels - 1); textureInfo.EnableFlipImage = false; } else { Gl.glBindTexture(Gl.GL_TEXTURE_2D, textureName); // Initialize bound texture state Gl.glTexParameteri(Gl.GL_TEXTURE_2D, Gl.GL_TEXTURE_WRAP_S, Gl.GL_REPEAT); Gl.glTexParameteri(Gl.GL_TEXTURE_2D, Gl.GL_TEXTURE_WRAP_T, Gl.GL_REPEAT); Gl.glTexParameteri(Gl.GL_TEXTURE_2D, Gl.GL_TEXTURE_MAG_FILTER, Gl.GL_LINEAR); } // If EnableFlipImage, we want to flip the image up side down if (textureInfo.EnableFlipImage) { int pixel_size = image.Pixels.Length; byte[] new_pixels = new byte[pixel_size]; for (int i = 0; i < image.Height; i++) { int source_i_offset = (image.Height - i - 1) * image.Width * image.ElementsPerPixel; int destin_i_offset = (i) * image.Width * image.ElementsPerPixel; for (int j = 0; j < image.Width; j++) { int j_offset = j * image.ElementsPerPixel; for (int k = 0; k < image.ElementsPerPixel; k++) { new_pixels[destin_i_offset + j_offset + k] = image.Pixels[source_i_offset + j_offset + k]; } } } image.Pixels = new_pixels; } if ((image.PixelFormat == PixelFormat.DXT1) || (image.PixelFormat == PixelFormat.DXT3) || (image.PixelFormat == PixelFormat.DXT5)) { int levels = image.Levels; if ((levels > 1) && CompressedTextureContainsAllMipmaps(image)) { Gl.glTexParameteri(Gl.GL_TEXTURE_2D, Gl.GL_TEXTURE_MIN_FILTER, Gl.GL_NEAREST_MIPMAP_LINEAR); } else { levels = 1; Gl.glTexParameteri(Gl.GL_TEXTURE_2D, Gl.GL_TEXTURE_MIN_FILTER, Gl.GL_LINEAR); } if (image.IsCubeMap) { CompressedTextureLoadPixelDataCUBEMAP(image, image.Levels); } else { CompressedTextureLoadPixelData(image, levels); } } else { Gl.glTexParameteri(Gl.GL_TEXTURE_2D, Gl.GL_TEXTURE_MIN_FILTER, Gl.GL_NEAREST_MIPMAP_LINEAR); Glu.gluBuild2DMipmaps( Gl.GL_TEXTURE_2D, image.ElementsPerPixel, image.Width, image.Height, image.OpenGlPixelFormat, Gl.GL_UNSIGNED_BYTE, image.Pixels); } Util3D.ReportErrors(); return(textureName); }