/// <summary> /// Render the vertices using current implementation. /// </summary> public void Render(PrimitiveType type) { // Notes: // GL.GetError() cannot be called upon render the immediate mode implementation. // There is no way to check automatically whether our data is valid or not. // Just make sure the specified colors, texcoords and positions are valid and correct. // Check the error before begin(?) GLChecker.CheckError(); // Specify primitive mode. GL.Begin((OpenTK.Graphics.OpenGL.PrimitiveType)((int)type)); // Set the Color, Texture Coordinate and Positions. for (int i = 0; i < _vertices.Length; i++) { // Color. GL.Color4(_vertices[i].Color.R, _vertices[i].Color.G, _vertices[i].Color.B, _vertices[i].Color.A); // TexCoord. GL.TexCoord2(_vertices[i].TexCoords.X, _vertices[i].TexCoords.Y); // Position. GL.Vertex2(_vertices[i].Position.X, _vertices[i].TexCoords.Y); } // Finished. GL.End(); // Check error again(?) GLChecker.CheckError(); }
public static void Bind(Shader shader) { // Make sure that we can use shaders if (!IsAvailable) { throw new NotSupportedException("Failed to bind or unbind shader. The system doesn't support shaders.\n" + "Shader.IsAvailable must return true in order to use Shader class."); } if (shader != null && shader._program > 0) { // Enable the program GLChecker.Check(() => GL.UseProgram(shader._program)); // Bind the textures shader.BindTextures(); // Bind the current texture if (shader._currentTexture != -1) { GLChecker.Check(() => GL.Uniform1(shader._currentTexture, 0)); } } else { // Bind no shader GLChecker.Check(() => GL.UseProgram(0)); } }
/// <summary> /// Releases all resources used by the <see cref="Texture"/>. /// </summary> public void Dispose() { if (_textureId > 0) { GLChecker.Check(() => GL.DeleteTexture(_textureId)); } }
/// <summary> /// Upload the Vertices into Buffer Data. /// </summary> public void Update(Vertex[] vertices) { // Assign vertices information _vertices = vertices; _length = vertices.Length; // Pin the vertices, prevent GC wipe this pointer using (var memory = new MemoryLock(_vertices)) { var pointer = memory.Address; // Calculate the stride and upload the vertices var stride = Vertex.Stride; GL.VertexPointer(2, VertexPointerType.Float, stride, pointer.Increment(0)); GLChecker.CheckError(); GL.TexCoordPointer(2, TexCoordPointerType.Float, stride, pointer.Increment(8)); GLChecker.CheckError(); GL.ColorPointer(4, ColorPointerType.UnsignedByte, stride, pointer.Increment(16)); GLChecker.CheckError(); } }
/// <summary> /// Render the vertices using current implementation. /// </summary> public void Render(PrimitiveType type) { // Draw the Vertices GLChecker.Check(() => GL.DrawArrays((OpenTK.Graphics.OpenGL.PrimitiveType)type, 0, _length) ); }
/// <summary> /// Upload the Vertices into Buffer Data. /// </summary> public void Update(Vertex[] vertices) { // Check whether the system support VBO if (!IsAvailable) { throw new NotSupportedException("The System doesn't support Vertex Buffer Object."); } // Check whether the handles are valid. if (_vertexBufferId <= 0) { Create(); } // Setup vertices information _count = vertices.Length; // Bind and Upload Vertices GLChecker.Check(() => GL.BindBuffer(BufferTarget.ArrayBuffer, _vertexBufferId)); GLChecker.Check(() => GL.BufferData(BufferTarget.ArrayBuffer, new IntPtr(vertices.Length * Vertex.Stride), vertices, BufferUsageHint.StaticDraw) ); // Set the Vertices Pointers GLChecker.Check(() => GL.VertexPointer(2, VertexPointerType.Float, Vertex.Stride, 0)); GLChecker.Check(() => GL.TexCoordPointer(2, TexCoordPointerType.Float, Vertex.Stride, Vector2.Stride)); GLChecker.Check(() => GL.ColorPointer(4, ColorPointerType.UnsignedByte, Vertex.Stride, Vector2.Stride + Vector2.Stride)); }
/// <summary> /// Releases all resources used by the <see cref="VertexBufferRenderer"/>. /// </summary> public void Dispose() { if (_vertexBufferId > 0) { GLChecker.Check(() => GL.DeleteBuffer(_vertexBufferId)); } }
/// <summary> /// Copy the <see cref="Texture"/> pixels to an <see cref="Image"/> instance. /// </summary> /// <returns><see cref="Image"/> containing the texture's pixels.</returns> public Image ToImage() { // Check for invalid / empty texture, just return empty bitmap if (_textureId <= 0 || (Size.Width == 0 && Size.Height == 0)) { return(new Bitmap(Size.Width, Size.Height)); } // Setup Bitmap data and use lockbit method to copy the pixels later Bitmap bmp = new Bitmap(Size.Width, Size.Height); BitmapData data = bmp.LockBits( new Rectangle(0, 0, bmp.Width, bmp.Height), ImageLockMode.WriteOnly, System.Drawing.Imaging.PixelFormat.Format32bppArgb); // Copy the texture pixels into bitmap data GLChecker.Check(() => GL.BindTexture(TextureTarget.Texture2D, _textureId)); GLChecker.Check(() => GL.GetTexImage(TextureTarget.Texture2D, 0, OpenTK.Graphics.OpenGL.PixelFormat.Bgra, PixelType.UnsignedByte, data.Scan0)); // Pixels copied, Unlock it bmp.UnlockBits(data); if (_pixelsFlipped) { bmp.RotateFlip(RotateFlipType.RotateNoneFlipY); } return(bmp); }
/// <summary> /// Update the texture from an <see cref="Image"/>. /// </summary> /// <param name="image"><see cref="Image"/> to copy to the texture.</param> /// <param name="x">X offset in the texture where to copy the source image</param> /// <param name="y">Y offset in the texture where to copy the source image</param> /// <param name="width">Width of the pixel region contained in image.</param> /// <param name="height">Height of the pixel region contained in image.</param> public void Update(Image image, int x, int y, int width, int height) { // Check if texture is previously created if (_textureId <= 0) { throw new AccessViolationException("Invalid Texture Handle."); } // Copy bitmap to specified region using (Bitmap bmp = new Bitmap(image)) { BitmapData data = bmp.LockBits(new Rectangle(0, 0, image.Width, image.Height), ImageLockMode.ReadOnly, System.Drawing.Imaging.PixelFormat.Format32bppArgb); GLChecker.Check(() => GL.BindTexture(TextureTarget.Texture2D, _textureId)); GLChecker.Check(() => GL.TexSubImage2D(TextureTarget.Texture2D, 0, x, y, width, height, OpenTK.Graphics.OpenGL.PixelFormat.Bgra, PixelType.UnsignedByte, data.Scan0)); GLChecker.Check(() => GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMinFilter, (int)(_isSmooth ? TextureMinFilter.Linear : TextureMinFilter.Nearest))); bmp.UnlockBits(data); // Force an OpenGL flush, so that the texture data will appear updated // in all contexts immediately (solves problems in multi-threaded apps) GLChecker.Check(() => GL.Flush()); } }
/// <summary> /// Specify values for matrix array uniform. /// </summary> /// <param name="name">The name of uniform variable in GLSL.</param> /// <param name="matrix">The array of matrix values.</param> public void SetUniformArray(string name, float[][] matrix) { int matrixSize = 0; if (matrix.Length == 3 * 3) { matrixSize = 3 * 3; } else if (matrix.Length == 4 * 4) { matrixSize = 4 * 4; } else { throw new ArgumentException("Matrix data must either 3x3 (9 elements) or 4x4 (16 elements)."); } float[] contiguous = new float[matrixSize * matrix.Length]; for (int i = 0; i < matrix.Length; ++i) { Array.Copy(matrix[i], 0, contiguous, matrixSize * i, matrixSize); } using (var binder = new UniformBinder(this, name)) { if (binder.Location != -1) { GLChecker.Check(() => GL.Uniform2(binder.Location, contiguous.Length, contiguous)); } } }
/// <summary> /// Generate Implementation Handle. /// This function will do nothing if VertexBufferObject is NOT supported or not preferred. /// </summary> public void Create() { // Check whether the system support VBO if (!IsAvailable) { throw new NotSupportedException("The System doesn't support Vertex Buffer Object."); } // Engine preference bool overrideHandle = true; // Check whether the handle is exist, and delete it if asked to do so. if (_vertexBufferId > 0 && overrideHandle) { GLChecker.Check(() => GL.DeleteBuffer(_vertexBufferId)); } // .. and throw the exception if its not asked to delete existing buffer. else if (_vertexBufferId > 0 && !overrideHandle) { throw new InvalidOperationException("Vertex Buffer Handle is already exist."); } // Generate the handle GLChecker.Check(() => GL.GenBuffers(1, out _vertexBufferId)); }
internal void InvalidateMipMap() { GLChecker.Check(() => GL.BindTexture(TextureTarget.Texture2D, _textureId)); GLChecker.Check(() => GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMinFilter, (int)(_isSmooth ? TextureMinFilter.Linear : TextureMinFilter.Nearest))); _hasMipmap = false; }
public void Dispose() { // Disable program object if (CurrentProgram > 0 && (CurrentProgram != SavedProgram)) { GLChecker.Check(() => GL.Arb.UseProgramObject(SavedProgram)); } }
/// <summary> /// Specify value for four component uniform. /// </summary> /// <param name="name">The name of uniform variable in GLSL.</param> /// <param name="vector">Value of the scalar.</param> public void SetUniform(string name, Vector4 <double> vector) { using (var binder = new UniformBinder(this, name)) { if (binder.Location != -1) { GLChecker.Check(() => GL.Uniform4(binder.Location, vector.X, vector.Y, vector.Z, vector.W)); } } }
/// <summary> /// Specify value for one component uniform. /// </summary> /// <param name="name">The name of uniform variable in GLSL.</param> /// <param name="x">Value of the scalar.</param> public void SetUniform(string name, double x) { using (var binder = new UniformBinder(this, name)) { if (binder.Location != -1) { GLChecker.Check(() => GL.Uniform1(binder.Location, x)); } } }
/// <summary> /// Get the maximum texture size allowed. /// </summary> /// <returns>Maximum size allowed for textures, in pixels.</returns> internal static int GetMaximumSize() { if (!_maxSizeChecked) { _maxSizeChecked = true; GLChecker.Check(() => GL.GetInteger(GetPName.MaxTextureSize, out _maxSize)); } return(_maxSize); }
/// <summary> /// Specify values for array uniform. /// </summary> /// <param name="name">The name of the uniform variable in GLSL.</param> /// <param name="scalarArray">The array of float values.</param> public void SetUniformArray(string name, float[] scalarArray) { using (var binder = new UniformBinder(this, name)) { if (binder.Location != -1) { GLChecker.Check(() => GL.Uniform1(binder.Location, scalarArray.Length, scalarArray)); } } }
/// <summary> /// Clear the entire target with a single color. /// </summary> /// <param name="color">Fill <see cref="Color"/> to use to clear the render target.</param> public void Clear(Color color) { if (Activate()) { ApplyTexture(null); GLChecker.Check(() => GL.ClearColor(color)); GLChecker.Check(() => GL.Clear(ClearBufferMask.ColorBufferBit)); } }
internal static int GetMaxTextureUnits() { int maxUnits = 0; GLChecker.Check(() => GL.GetInteger(GetPName.MaxCombinedTextureImageUnits, out maxUnits) ); return(maxUnits); }
/// <summary> /// Specify values for array uniform. /// </summary> /// <param name="name">The name of uniform variable in GLSL.</param> /// <param name="vector">Value of the scalar.</param> public void SetUniformArray(string name, Vector4 <double>[] vector) { using (var binder = new UniformBinder(this, name)) { if (binder.Location != -1) { double[] contiguous = vector.Flatten(); GLChecker.Check(() => GL.Uniform2(binder.Location, contiguous.Length, contiguous)); } } }
/// <summary> /// Generates a MipMap using the current <see cref="Texture"/> data. /// </summary> /// <returns></returns> public void GenerateMipMap() { if (!GLExtensions.IsAvailable("GL_EXT_framebuffer_object")) { return; } GLChecker.Check(() => GL.BindTexture(TextureTarget.Texture2D, _textureId)); GLChecker.Check(() => GL.GenerateMipmap(GenerateMipmapTarget.Texture2D)); GLChecker.Check(() => GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMinFilter, (int)(_isSmooth ? TextureMinFilter.LinearMipmapLinear : TextureMinFilter.NearestMipmapLinear))); _hasMipmap = true; return; }
private void ApplyTransform(Transform transform) { // ModelView is always preferred in all cases of modules. // All operations that interact with the matrix will switch back the mode to ModelView. // So no need to change the matrix mode to ModelView. // Null transform should be replaced by identity transform if (transform == null) { transform = Transform.Identity; } // Apply Transformation Matrix GLChecker.Check(() => GL.LoadMatrix(transform.Matrix)); }
private void ApplyBlendMode(BlendMode mode) { if (GLExtensions.IsAvailable("GL_EXT_blend_func_separate")) { GLChecker.Check(() => GL.BlendFuncSeparate((BlendingFactorSrc)FactorToGL(mode.ColorSrcFactor), (BlendingFactorDest)FactorToGL(mode.ColorDstFactor), (BlendingFactorSrc)FactorToGL(mode.AlphaSrcFactor), (BlendingFactorDest)FactorToGL(mode.AlphaDstFactor)) ); } else { var src = (BlendingFactorSrc)FactorToGL(mode.ColorSrcFactor); var dst = (BlendingFactorDest)FactorToGL(mode.ColorDstFactor); GLChecker.Check(() => GL.BlendFunc(src, dst) ); } if (GLExtensions.IsAvailable("GL_EXT_blend_minmax") && GLExtensions.IsAvailable("GL_EXT_blend_subtract")) { if (GLExtensions.IsAvailable("GL_EXT_blend_equation_separate")) { GLChecker.Check(() => GL.Ext.BlendEquationSeparate( (BlendEquationModeExt)EquationToGL(mode.ColorEquation), (BlendEquationModeExt)EquationToGL(mode.AlphaEquation)) ); } else { GLChecker.Check(() => GL.Ext.BlendEquation(EquationToGL(mode.ColorEquation)) ); } } else if ((mode.ColorEquation != BlendMode.Equation.Add) || (mode.AlphaEquation != BlendMode.Equation.Add)) { if (!_isBlendingWarned) { Logger.Warning("OpenGL extension EXT_blend_minmax and / or EXT_blend_subtract unavailable.\n" + "Selecting a blend equation is not possible\n" + "Ensure that hardware acceleration is enabled if available."); _isBlendingWarned = true; } } Cache.LastBlendMode = mode; }
public void Dispose() { // Return to visible frame buffer GLChecker.Check(() => GL.Ext.BindFramebuffer(FramebufferTarget.FramebufferExt, 0)); GLChecker.Check(() => GL.DrawBuffer(DrawBufferMode.Back)); if (_frameBuffer > 0) { GLChecker.Check(() => GL.Ext.DeleteFramebuffer(_frameBuffer)); } if (_depthBuffer > 0) { GLChecker.Check(() => GL.Ext.DeleteFramebuffer(_depthBuffer)); } }
private void BindTextures() { int index = 1; foreach (KeyValuePair <int, Texture> texture in _textures) { GLChecker.Check(() => GL.Uniform1(texture.Key, index)); GLChecker.Check(() => GL.ActiveTexture(TextureUnit.Texture0 + index)); Texture.Bind(texture.Value); index++; } // Make sure that the texture unit which is left active is the number 0 GLChecker.Check(() => GL.ActiveTexture(TextureUnit.Texture0)); }
/// <summary> /// Initializes a new instance of the <see cref="Texture"/> class /// from an existing <see cref="Image"/> instance with specified region. /// </summary> /// <param name="image">The existing <see cref="Image"/> instance.</param> /// <param name="region">The area of the <see cref="Image"/> to load.</param> public Texture(Image image, Rectangle region) : this() { // Retrieve the image size int areaWidth = image.Width; int areaHeight = image.Height; // Load the entire image if the source area is either empty or contains the whole image if (region.Width == 0 || (region.Height == 0) || ((region.Left <= 0) && (region.Top <= 0) && (region.Width >= areaWidth) && (region.Height >= areaHeight))) { // Load the entire image Create(image.Width, image.Height, false); Update(image); } else { // Clamp the region size to valid value int left = (region.Left < 0) ? 0 : region.Left; int top = (region.Top < 0) ? 0 : region.Top; int width = (region.Left + region.Width > areaWidth) ? areaWidth - region.Left : region.Width; int height = (region.Top + region.Height > areaHeight) ? areaHeight - region.Top : region.Height; Create(width, height, false); // Copy bitmap to specified region using (Bitmap bmp = new Bitmap(image)) { BitmapData data = bmp.LockBits(new Rectangle(left, top, width, height), ImageLockMode.ReadOnly, System.Drawing.Imaging.PixelFormat.Format32bppArgb); GLChecker.Check(() => GL.BindTexture(TextureTarget.Texture2D, _textureId)); GLChecker.Check(() => GL.TexImage2D(TextureTarget.Texture2D, 0, 0, 0, width, height, OpenTK.Graphics.OpenGL.PixelFormat.Bgra, PixelType.UnsignedByte, data.Scan0)); GLChecker.Check(() => GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMinFilter, (int)(_isSmooth ? TextureMinFilter.Linear : TextureMinFilter.Nearest))); bmp.UnlockBits(data); // Force an OpenGL flush, so that the texture data will appear updated // in all contexts immediately (solves problems in multi-threaded apps) GLChecker.Check(() => GL.Flush()); } } }
/// <summary> /// Bind the existing <see cref="Texture"/> to texturing target. /// If the <see cref="Texture"/> is null, it will unbind any <see cref="Texture"/> from texturing target. /// </summary> /// <param name="texture">Texture to bind.</param> public static void Bind(Texture texture, CoordinateType type = CoordinateType.Pixel) { if (texture != null && texture._textureId > 0) { Matrix4 matrix = new Matrix4 (1f, 0f, 0f, 0f, 0f, 1f, 0f, 0f, 0f, 0f, 1f, 0f, 0f, 0f, 0f, 1f); // Convert to normalized one ([0..1]) if (type == CoordinateType.Pixel) { matrix[0, 0] = 1f / texture.Size.Width; matrix[1, 1] = 1f / texture.Size.Height; } if (texture._pixelsFlipped) { matrix[1, 1] = -matrix[1, 1]; matrix[3, 1] = texture.Size.Height / texture._actualSize.Height; } // Bind the texture GLChecker.Check(() => GL.BindTexture(TextureTarget.Texture2D, texture._textureId)); // Apply the texture matrix GLChecker.Check(() => GL.MatrixMode(MatrixMode.Texture)); GLChecker.Check(() => GL.LoadMatrix(ref matrix)); // Back to ModelView to prevent problems with the RenderTarget GLChecker.Check(() => GL.MatrixMode(MatrixMode.Modelview)); } else { // Bind no texture (Unbind) GLChecker.Check(() => GL.BindTexture(TextureTarget.Texture2D, 0)); // Reset Texture Matrix GLChecker.Check(() => GL.MatrixMode(MatrixMode.Texture)); GLChecker.Check(() => GL.LoadIdentity()); // RenderTarget always expect ModelView mode, so let's change it back GLChecker.Check(() => GL.MatrixMode(MatrixMode.Modelview)); } }
/// <summary> /// Pop all previous OpenGL States. /// </summary> public void PopGLStates() { #if DEBUG var error = GLChecker.GetError(); if (error != ErrorCode.NoError) { Logger.Warning("OpenGL Error ({1}) has detected in user code.\n" + "Make sure to check the error when using custom OpenGL codes.", error); } #endif GL.MatrixMode(MatrixMode.Modelview); GL.PopMatrix(); GL.MatrixMode(MatrixMode.Projection); GL.PopMatrix(); GL.MatrixMode(MatrixMode.Texture); GL.PopMatrix(); // Reset GL States Reset(); }
public UniformBinder(Shader shader, string name) { SavedProgram = 0; CurrentProgram = shader._program; Location = -1; var uniform = this; if (CurrentProgram > 0) { // Enable program object GLChecker.Check(() => SavedProgram = GL.Arb.GetHandle(ArbShaderObjects.ProgramObjectArb)); if (CurrentProgram != SavedProgram) { GL.Arb.UseProgramObject(CurrentProgram); } // Store uniform location for further use outside constructor Location = shader.GetUniformLocation(name); } }
/// <summary> /// Specify value for matrix uniform. /// </summary> /// <param name="name">The name of uniform variable in GLSL.</param> /// <param name="matrix">Value of the scalar.</param> public void SetUniform(string name, float[] matrix) { using (var binder = new UniformBinder(this, name)) { if (binder.Location != -1) { if (matrix.Length == 9) { GLChecker.Check(() => GL.UniformMatrix3(binder.Location, 1, false, matrix)); } else if (matrix.Length == 16) { GLChecker.Check(() => GL.UniformMatrix4(binder.Location, 1, true, matrix)); } else { throw new ArgumentException("Matrix data must either 3x3 (9 elements) or 4x4 (16 elements)."); } } } }