private void LoadBitmap(Bitmap BitmapImage, bool FlipY = true) { /* .net library has methods for converting many image formats so I exploit that by using * .net to convert any filetype to a bitmap. Then the bitmap is locked into memory so * that the garbage collector doesn't touch it, and it is read via OpenGL glTexImage2D. */ if (FlipY) { BitmapImage.RotateFlip(RotateFlipType.RotateNoneFlipY); // bitmaps read from bottom up, so flip it } Size = BitmapImage.Size; // must be Format32bppArgb file format, so convert it if it isn't in that format BitmapData bitmapData = BitmapImage.LockBits(new Rectangle(0, 0, BitmapImage.Width, BitmapImage.Height), ImageLockMode.ReadOnly, System.Drawing.Imaging.PixelFormat.Format32bppArgb); // set the texture target and then generate the texture ID TextureTarget = TextureTarget.Texture2D; TextureID = GlUtility.GenTexture(); GL.PixelStore(PixelStoreParameter.UnpackAlignment, 1); // set pixel alignment GL.BindTexture(TextureTarget, TextureID); // bind the texture to memory in OpenGL GL.TexImage2D(TextureTarget, 0, PixelInternalFormat.Rgba8, BitmapImage.Width, BitmapImage.Height, 0, PixelFormat.Bgra, PixelType.UnsignedByte, bitmapData.Scan0); GL.TexParameter(TextureTarget, TextureParameterName.TextureMagFilter, (int)TextureMagFilter.Linear); GL.TexParameter(TextureTarget, TextureParameterName.TextureMinFilter, (int)TextureMinFilter.LinearMipmapLinear); GL.GenerateMipmap(GenerateMipmapTarget.Texture2D); BitmapImage.UnlockBits(bitmapData); BitmapImage.Dispose(); }
/// <summary> /// Loads a compressed DDS file into an OpenGL texture. /// </summary> /// <param name="ResourceFile">The path to the DDS file.</param> private void LoadDDS(string ResourceFile) { using (BinaryReader stream = new BinaryReader(new FileStream(ResourceFile, FileMode.Open))) { string filecode = new string(stream.ReadChars(4)); if (filecode != "DDS ") // first 4 chars should be "DDS " { throw new Exception("File was not a DDS file format."); } DDS.DDSURFACEDESC2 imageData = DDS.DDSURFACEDESC2.FromBinaryReader(stream); //new DDS.DDSURFACEDESC2(stream); // read the DirectDraw surface descriptor this.Size = new Size((int)imageData.Width, (int)imageData.Height); if (imageData.LinearSize == 0) { throw new Exception("The linear scan line size was zero."); } bool compressed = true; int factor = 0, buffersize = 0, blocksize = 0; InternalFormat format; PixelInternalFormat pixelFormat; switch (imageData.PixelFormat.FourCC) // check the compression type { case "DXT1": // DXT1 compression ratio is 8:1 format = InternalFormat.CompressedRgbaS3tcDxt1Ext; pixelFormat = PixelInternalFormat.CompressedRgbaS3tcDxt1Ext; factor = 2; blocksize = 8; break; case "DXT3": // DXT3 compression ratio is 4:1 format = InternalFormat.CompressedRgbaS3tcDxt3Ext; pixelFormat = PixelInternalFormat.CompressedRgbaS3tcDxt3Ext; factor = 4; blocksize = 16; break; case "DXT5": // DXT5 compression ratio is 4:1 format = InternalFormat.CompressedRgbaS3tcDxt5Ext; pixelFormat = PixelInternalFormat.CompressedRgbaS3tcDxt5Ext; factor = 4; blocksize = 16; break; default: compressed = false; if (imageData.PixelFormat.ABitMask == 0xf000 && imageData.PixelFormat.RBitMask == 0x0f00 && imageData.PixelFormat.GBitMask == 0x00f0 && imageData.PixelFormat.BBitMask == 0x000f && imageData.PixelFormat.RGBBitCount == 16) { format = InternalFormat.Rgba; pixelFormat = PixelInternalFormat.Rgba; } else if (imageData.PixelFormat.ABitMask == unchecked ((int)0xff000000) && imageData.PixelFormat.RBitMask == 0x00ff0000 && imageData.PixelFormat.GBitMask == 0x0000ff00 && imageData.PixelFormat.BBitMask == 0x000000ff && imageData.PixelFormat.RGBBitCount == 32) { format = InternalFormat.Rgba; pixelFormat = PixelInternalFormat.Rgba; } else { throw new Exception(string.Format("File compression \"{0}\" is not supported.", imageData.PixelFormat.FourCC)); } break; } if (imageData.LinearSize != 0) { buffersize = (int)((imageData.MipmapCount > 1) ? imageData.LinearSize * factor : imageData.LinearSize); } else { buffersize = (int)(stream.BaseStream.Length - stream.BaseStream.Position); } // read the pixel data and then pin it to memory so that the garbage collector // doesn't shuffle the data around while OpenGL is decompressing it byte[] pixels = stream.ReadBytes(buffersize); GCHandle pinned = GCHandle.Alloc(pixels, GCHandleType.Pinned); try { TextureTarget = (imageData.Height == 1 || imageData.Width == 1) ? TextureTarget.Texture1D : TextureTarget.Texture2D; TextureID = GlUtility.GenTexture(); GL.BindTexture(TextureTarget, TextureID); GL.TexParameter(TextureTarget, TextureParameterName.TextureMinFilter, (int)TextureMinFilter.Linear); GL.TexParameter(TextureTarget, TextureParameterName.TextureMagFilter, (int)TextureMagFilter.Linear); int nOffset = 0, nWidth = (int)imageData.Width, nHeight = (int)imageData.Height; for (int i = 0; i < (imageData.MipmapCount == 0 ? 1 : imageData.MipmapCount); ++i) { if (nWidth == 0) { nWidth = 1; // smallest mipmap is 1x1 pixels } if (nHeight == 0) { nHeight = 1; } int nSize = 0; if (compressed) { nSize = ((nWidth + 3) / 4) * ((nHeight + 3) / 4) * blocksize; GL.CompressedTexImage2D(TextureTarget, i, format, nWidth, nHeight, 0, nSize, (IntPtr)(pinned.AddrOfPinnedObject().ToInt64() + nOffset)); } else { PixelType pixelType = imageData.PixelFormat.RGBBitCount == 16 ? PixelType.UnsignedShort4444Reversed : PixelType.UnsignedInt8888Reversed; nSize = nWidth * nHeight * imageData.PixelFormat.RGBBitCount / 8; GL.TexImage2D(TextureTarget, i, pixelFormat, nWidth, nHeight, 0, PixelFormat.Bgra, pixelType, (IntPtr)(pinned.AddrOfPinnedObject().ToInt64() + nOffset)); } nOffset += nSize; nWidth /= 2; nHeight /= 2; } } catch (Exception) { // There was some sort of Dll related error, or the target GPU does not support glCompressedTexImage2DARB throw; } finally { pinned.Free(); } } }