/// <summary> /// Creates a standard VBO of type T where the length of the VBO is less than or equal to the length of the data. /// </summary> /// <typeparam name="T">The type of the data being stored in the VBO (make sure it's byte aligned).</typeparam> /// <param name="target">The VBO BufferTarget (usually ArrayBuffer or ElementArrayBuffer).</param> /// <param name="data">The data to store in the VBO.</param> /// <param name="hint">The buffer usage hint (usually StaticDraw).</param> /// <param name="length">The length of the VBO (will take the first 'length' elements from data).</param> /// <returns>The buffer ID of the VBO on success, 0 on failure.</returns> public static uint CreateVBO <T>(BufferTarget target, [In, Out] T[] data, BufferUsageHint hint, int length) where T : struct { uint vboHandle = Gl.GenBuffer(); if (vboHandle == 0) { return(0); } int size = length * Marshal.SizeOf(typeof(T)); #if MEMORY_LOGGER MemoryLogger.AllocateVBO(vboHandle, size); #endif Gl.BindBuffer(target, vboHandle); Gl.BufferData <T>(target, size, data, hint); Gl.BindBuffer(target, 0); return(vboHandle); }
/// <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; PixelInternalFormat format; switch (imageData.PixelFormat.FourCC) // check the compression type { case "DXT1": // DXT1 compression ratio is 8:1 format = PixelInternalFormat.CompressedRgbaS3tcDxt1Ext; factor = 2; blocksize = 8; break; case "DXT3": // DXT3 compression ratio is 4:1 format = PixelInternalFormat.CompressedRgbaS3tcDxt3Ext; factor = 4; blocksize = 16; break; case "DXT5": // DXT5 compression ratio is 4:1 format = 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 = 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 = 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 { this.TextureTarget = (imageData.Height == 1 || imageData.Width == 1) ? TextureTarget.Texture1D : TextureTarget.Texture2D; this.TextureID = Gl.GenTexture(); Gl.BindTexture(TextureTarget, TextureID); Gl.TexParameteri(TextureTarget, TextureParameterName.TextureMinFilter, TextureParameter.Linear); Gl.TexParameteri(TextureTarget, TextureParameterName.TextureMagFilter, TextureParameter.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, format, nWidth, nHeight, 0, PixelFormat.Bgra, pixelType, (IntPtr)(pinned.AddrOfPinnedObject().ToInt64() + nOffset)); } nOffset += nSize; nWidth /= 2; nHeight /= 2; } #if MEMORY_LOGGER MemoryLogger.AllocateTexture(TextureID, Size); #endif } catch (Exception) { // There was some sort of Dll related error, or the target GPU does not support glCompressedTexImage2DARB throw; } finally { pinned.Free(); } } }