/// <summary> /// 链接顶点属性(Enable Or Disable) /// </summary> /// <param name="attrs"></param> internal void SetVertexAttributeArray(bool[] attrs) { for (int i = 0; i < attrs.Length; i++) { if (attrs[i] && !_enabledVertexAttributes.Contains(i)) { _enabledVertexAttributes.Add(i); GL.EnableVertexAttribArray(i); GraphicsExtensions.CheckGLError(); } else if (!attrs[i] && _enabledVertexAttributes.Contains(i)) { _enabledVertexAttributes.Remove(i); GL.DisableVertexAttribArray(i); GraphicsExtensions.CheckGLError(); } } }
/// <summary> /// 设定OpenGL 渲染窗口维度 /// </summary> /// <param name="value"></param> private void PlatformSetViewport(ref Viewport value) { if (IsRenderTargetBound) { GL.Viewport(value.X, value.Y, value.Width, value.Height); } else { GL.Viewport(value.X, PresentationParameters.BackBufferHeight - value.Y - value.Height, value.Width, value.Height); } GraphicsExtensions.LogGLError("GraphicsDevice.Viewport_set() GL.Viewport"); #if GLES GL.DepthRange(value.MinDepth, value.MaxDepth); #endif GraphicsExtensions.LogGLError("GraphicsDevice.Viewport_set() GL.DepthRange"); _vertexShaderDirty = true; }
/// <summary> /// 生成顶点缓冲对象 /// </summary> void GenerateIfRequired() { if (vbo == 0) { GL.GenBuffers(1, out this.vbo);// GraphicsExtensions.CheckGLError(); //bind to the buffer,Future commands will affect this buffer specifically GL.BindBuffer(BufferTarget.ArrayBuffer, this.vbo); GraphicsExtensions.CheckGLError(); //定义的顶点数据复制到缓冲的内存中 //parameter1:目标缓冲的类型 //parameter2:传输数据的大小(以字节为单位) //parameter3:希望发送的实际数据 //parameter4:显卡如何管理给定的数据 (StreamDraw:数据每次绘制都会改变 staticDraw:数据不会或几乎不会改变) GL.BufferData(BufferTarget.ArrayBuffer, new IntPtr(VertexDeclaration.VertexStride * VertexCount), IntPtr.Zero, _isDynamic ? BufferUsageHint.StreamDraw : BufferUsageHint.StaticDraw); GraphicsExtensions.CheckGLError(); } }
/// <summary> /// 链接顶点属性 /// (顶点数据的哪一部分对应着色器的哪一个顶点属性) /// </summary> /// <param name="shader"></param> /// <param name="offset"></param> /// <param name="programHash"></param> internal void Apply(Shader shader, IntPtr offset, int programHash) { VertexDeclarationAttributeInfo attrInfo; if (!shaderAttributeInfo.TryGetValue(programHash, out attrInfo)) { // Get the vertex attribute info and cache it attrInfo = new VertexDeclarationAttributeInfo(GraphicsDevice.MaxVertexAttributes); foreach (var ve in InternalVertexElements) { var attributeLocation = shader.GetAttribLocation(ve.VertexElementUsage, ve.UsageIndex); if (attributeLocation >= 0) { attrInfo.Elements.Add(new VertexDeclarationAttributeInfo.Element { Offset = ve.Offset, AttributeLocation = attributeLocation, NumberOfElements = ve.VertexElementFormat.OpenGLNumberOfElements(), VertexAttribPointerT = ve.VertexElementFormat.OpenGLVertexAttribPointerT(), Normalized = ve.OpenGLVertexAttribNormalized(), }); attrInfo.EnabledAttributes[attributeLocation] = true; } } shaderAttributeInfo.Add(programHash, attrInfo); } //Apply the vertex attribute info foreach (var element in attrInfo.Elements) { GL.VertexAttribPointer(element.AttributeLocation, element.NumberOfElements, element.VertexAttribPointerT, element.Normalized, this.VertexStride, (IntPtr)(offset.ToInt64() + element.Offset)); GraphicsExtensions.CheckGLError(); } GraphicsDevice.SetVertexAttributeArray(attrInfo.EnabledAttributes); }
/// <summary> /// 链接着色器->着色器程序 /// </summary> /// <param name="pixelShader"></param> /// <param name="vertexShader"></param> /// <returns></returns> private ShaderProgram Link(Shader pixelShader, Shader vertexShader) { var program = GL.CreateProgram(); GraphicsExtensions.CheckGLError(); GL.AttachShader(program, vertexShader.GetShaderHandle()); GraphicsExtensions.CheckGLError(); GL.AttachShader(program, pixelShader.GetShaderHandle()); GraphicsExtensions.CheckGLError(); GL.LinkProgram(program); GraphicsExtensions.CheckGLError(); GL.UseProgram(program); GraphicsExtensions.CheckGLError(); vertexShader.GetVertexAttributeLocations(program); pixelShader.ApplySamplerTextureUnits(program); var linked = 0; GL.GetProgram(program, GetProgramParameterName.LinkStatus, out linked); if (linked == (int)Bool.False) { GL.DetachShader(program, vertexShader.GetShaderHandle()); GL.DetachShader(program, pixelShader.GetShaderHandle()); GL.DeleteProgram(program); throw new InvalidOperationException("Unable to link effect program"); } return(new ShaderProgram(program)); }
/// <summary> /// /// </summary> private unsafe void ActivateShaderProgram() { var shaderProgram = _programCache.GetProgram(VertexShader, PixelShader); if (shaderProgram.Program == -1) { return; } if (_shaderProgram != shaderProgram) { GL.UseProgram(shaderProgram.Program); GraphicsExtensions.CheckGLError(); _shaderProgram = shaderProgram; } var posFixupLoc = shaderProgram.GetUnitformLocation("posFixup"); if (posFixupLoc == -1) { return; } _posFilxup[0] = 1.0f; _posFilxup[1] = 1.0f; _posFilxup[2] = (63.0f / 64.0f) / Viewport.Width; _posFilxup[3] = -(63.0f / 64.0f) / Viewport.Height; if (IsRenderTargetBound) { } fixed(float *floatPtr = _posFilxup) { GL.Uniform4(posFixupLoc, 1, floatPtr); } GraphicsExtensions.CheckGLError(); }
/// <summary> /// /// </summary> private void PlatformSetup() { MaxTextureSlots = 16; GL.GetInteger(GetPName.MaxTextureImageUnits, out MaxTextureSlots); GraphicsExtensions.CheckGLError(); GL.GetInteger(GetPName.MaxVertexAttribs, out MaxVertexAttributes); GraphicsExtensions.CheckGLError(); GL.GetInteger(GetPName.MaxTextureSize, out MaxTextureSize); GraphicsExtensions.CheckGLError(); SpriteBatch.NeedsHalfPixelOffset = true; try { string version = GL.GetString(StringName.Version); string[] versionSplit = version.Split(' '); if (versionSplit.Length > 2 && versionSplit[0].Equals("OpenGL") && versionSplit[1].Equals("ES")) { glMajorVersion = Convert.ToInt32(versionSplit[2].Substring(0, 1)); glMinorVersion = Convert.ToInt32(versionSplit[2].Substring(2, 1)); } else { glMajorVersion = 1; glMinorVersion = 1; } } catch (FormatException) { glMajorVersion = 1; glMinorVersion = 1; } _extensions = GetGLExtensions(); }
/// <summary> /// 创建一个帧缓冲的纹理 /// </summary> private void GenerateGLTextureIfRequired() { if (this.glTexture < 0) { GL.GenTextures(1, out this.glTexture); GraphicsExtensions.CheckGLError(); var wrap = TextureWrapMode.Repeat; if ((width & (width - 1)) != 0 || ((height & (height - 1)) != 0)) { wrap = TextureWrapMode.ClampToEdge; } GL.BindTexture(TextureTarget.Texture2D, this.glTexture); GraphicsExtensions.CheckGLError(); GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMinFilter, (_levelCount > 1) ? (int)TextureMinFilter.LinearMipmapLinear : (int)TextureMinFilter.Linear); GraphicsExtensions.CheckGLError(); GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMagFilter, (int)TextureMagFilter.Linear); GraphicsExtensions.CheckGLError(); GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapS, (int)wrap); GraphicsExtensions.CheckGLError(); GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapT, (int)wrap); GraphicsExtensions.CheckGLError(); } }
/// <summary> /// /// </summary> /// <typeparam name="T"></typeparam> /// <param name="offsetInBytes"></param> /// <param name="data"></param> /// <param name="startIndex"></param> /// <param name="elementCount"></param> /// <param name="options"></param> private void BufferData <T>(int offsetInBytes, T[] data, int startIndex, int elementCount, SetDataOptions options) where T : struct { GenerateIfRequired(); var elementSizeInByte = Marshal.SizeOf(typeof(T)); var sizeInBytes = elementSizeInByte * elementCount; var dataHandle = GCHandle.Alloc(data, GCHandleType.Pinned); var dataPtr = (IntPtr)(dataHandle.AddrOfPinnedObject().ToInt64() + startIndex * elementSizeInByte); var bufferSize = IndexCount * (IndexElementSize == IndexElementSize.SixteenBits ? 2 : 4); GL.BindBuffer(BufferTarget.ElementArrayBuffer, ibo); GraphicsExtensions.CheckGLError(); if (options == SetDataOptions.Discard) { GL.BufferData(BufferTarget.ElementArrayBuffer, (IntPtr)bufferSize, IntPtr.Zero, _isDynamic ? OpenTK.Graphics.ES20.BufferUsage.StreamDraw : OpenTK.Graphics.ES20.BufferUsage.StaticDraw); GraphicsExtensions.CheckGLError(); } GL.BufferSubData(BufferTarget.ElementArrayBuffer, (IntPtr)offsetInBytes, (IntPtr)sizeInBytes, dataPtr); GraphicsExtensions.CheckGLError(); dataHandle.Free(); }
/// <summary> /// /// </summary> /// <typeparam name="T"></typeparam> /// <param name="level">多级渐远纹理的级别</param> /// <param name="arraySize"></param> /// <param name="rect"></param> /// <param name="data">图像数据</param> /// <param name="startIndex"></param> /// <param name="elementCount"></param> private void PlatformSetData <T>(int level, int arraySize, Rectangle rect, T[] data, int startIndex, int elementCount) where T : struct { Threading.BlockOnUIThread(() => { var elementSizeInByte = Marshal.SizeOf(typeof(T)); var dataHandle = GCHandle.Alloc(data, GCHandleType.Pinned); try { var startBytes = startIndex * elementSizeInByte; var dataPtr = (IntPtr)(dataHandle.AddrOfPinnedObject().ToInt64() + startBytes); //Store the current bound texture var prevTexture = GraphicsExtensions.GetBoundTexture2D(); GenerateGLTextureIfRequired(); GL.BindTexture(TextureTarget.Texture2D, this.glTexture); GraphicsExtensions.CheckGLError(); if (glFormat == (PixelFormat)GLPixelFormat.CompressedTextureFormats) { } else { GL.TexSubImage2D(TextureTarget.Texture2D, level, rect.X, rect.Y, rect.Width, rect.Height, glFormat, glType, dataPtr); GraphicsExtensions.CheckGLError(); } //Restore the bound texture. GL.BindTexture(TextureTarget.Texture2D, prevTexture); GraphicsExtensions.CheckGLError(); } finally { dataHandle.Free(); } }); }
internal virtual void BindFramebuffer(int framebuffer) { GL.BindFramebuffer(FramebufferTarget.Framebuffer, framebuffer); GraphicsExtensions.CheckGLError(); }
/// <summary> /// /// </summary> /// <param name="device"></param> /// <param name="force"></param> internal void PlatformApplyState(GraphicsDevice device, bool force = false) { var offscreen = device.IsRenderTargetBound; if (force) { GL.Disable(EnableCap.Dither); } if (CullMode == CullMode.None) { GL.Disable(EnableCap.CullFace); GraphicsExtensions.CheckGLError(); } else { GL.Enable(EnableCap.CullFace); GraphicsExtensions.CheckGLError(); GL.CullFace(CullFaceMode.Back);// 只剔除背面 GraphicsExtensions.CheckGLError(); if (CullMode == CullMode.CullClockwiseFace) { if (offscreen) { GL.FrontFace(FrontFaceDirection.Cw); //顺时针方向为正面 } else { GL.FrontFace(FrontFaceDirection.Ccw); //逆时针方向为正面 } GraphicsExtensions.CheckGLError(); } else { if (offscreen) { GL.FrontFace(FrontFaceDirection.Ccw); } else { GL.FrontFace(FrontFaceDirection.Cw); } GraphicsExtensions.CheckGLError(); } } if (FillMode != FillMode.Solid) { throw new NotImplementedException(); } if (force || this.ScissorTestEnable != device._lastRasterizerState.ScissorTestEnable) { if (ScissorTestEnable) { GL.Enable(EnableCap.ScissorTest); } else { GL.Disable(EnableCap.ScissorTest); } GraphicsExtensions.CheckGLError(); device._lastRasterizerState.ScissorTestEnable = this.ScissorTestEnable; } if (force || this.DepthBias != device._lastRasterizerState.DepthBias || this.SlopeScaleDepthBias != device._lastRasterizerState.SlopeScaleDepthBias) { if (this.DepthBias != 0 || this.SlopeScaleDepthBias != 0) { } else { GL.Disable(EnableCap.PolygonOffsetFill); } GraphicsExtensions.CheckGLError(); device._lastRasterizerState.DepthBias = this.DepthBias; device._lastRasterizerState.SlopeScaleDepthBias = this.SlopeScaleDepthBias; } if (device.GraphicsCapabilities.SupportsDepthClamp && (force || this.DepthClipEnable != device._lastRasterizerState.DepthClipEnable)) { if (!DepthClipEnable) { GL.Enable((EnableCap)0x864F); } else { GL.Disable((EnableCap)0x864F); } GraphicsExtensions.CheckGLError(); device._lastRasterizerState.DepthClipEnable = this.DepthClipEnable; } }
/// <summary> /// /// </summary> /// <param name="device"></param> /// <param name="force"></param> internal void PlatformApplyState(GraphicsDevice device, bool force = false) { //Enable/Disable Éî¶È»º³å if (force || this.DepthBufferEnable != device._lastDepthStencilState.DepthBufferEnable) { if (!DepthBufferEnable) { GL.Disable(EnableCap.DepthTest); GraphicsExtensions.CheckGLError(); } else { GL.Enable(EnableCap.DepthTest); GraphicsExtensions.CheckGLError(); } device._lastDepthStencilState.DepthBufferEnable = this.DepthBufferEnable; } if (force || this.DepthBufferFunction != device._lastDepthStencilState.DepthBufferFunction) { GL.DepthFunc(this.DepthBufferFunction.GetDepthFunction()); GraphicsExtensions.CheckGLError(); device._lastDepthStencilState.DepthBufferFunction = this.DepthBufferFunction; } if (force || this.DepthBufferWriteEnable != device._lastDepthStencilState.DepthBufferWriteEnable) { GL.DepthMask(DepthBufferWriteEnable); GraphicsExtensions.CheckGLError(); device._lastDepthStencilState.DepthBufferWriteEnable = this.DepthBufferWriteEnable; } if (force || this.StencilEnable != device._lastDepthStencilState.StencilEnable) { if (!StencilEnable) { GL.Disable(EnableCap.StencilTest); GraphicsExtensions.CheckGLError(); } else { GL.Enable(EnableCap.StencilTest); GraphicsExtensions.CheckGLError(); } device._lastDepthStencilState.StencilEnable = this.StencilEnable; } if (force || this.StencilWriteMask != device._lastDepthStencilState.StencilWriteMask) { GL.StencilMask(this.StencilWriteMask); GraphicsExtensions.CheckGLError(); device._lastDepthStencilState.StencilWriteMask = StencilWriteMask; } if (this.TwoSidedStencilMode) { } else { if (force || this.TwoSidedStencilMode != device._lastDepthStencilState.TwoSidedStencilMode || this.StencilFunction != device._lastDepthStencilState.StencilFunction || this.ReferenceStencil != device._lastDepthStencilState.ReferenceStencil || this.StencilMask != device._lastDepthStencilState.StencilMask) { GL.StencilFunc(GetStencilFunc(this.StencilFunction), ReferenceStencil, this.StencilMask); GraphicsExtensions.CheckGLError(); device._lastDepthStencilState.StencilFunction = StencilFunction; device._lastDepthStencilState.ReferenceStencil = ReferenceStencil; device._lastDepthStencilState.StencilMask = StencilMask; } if (force || this.TwoSidedStencilMode != device._lastDepthStencilState.TwoSidedStencilMode || this.StencilFail != device._lastDepthStencilState.StencilFail || this.StencilDetphBufferFail != device._lastDepthStencilState.StencilDetphBufferFail || this.StencilPass != device._lastDepthStencilState.StencilPass) { GL.StencilOp(GetStencilOp(this.StencilFail), GetStencilOp(this.StencilDetphBufferFail), GetStencilOp(this.StencilPass)); GraphicsExtensions.CheckGLError(); device._lastDepthStencilState.StencilFail = this.StencilFail; device._lastDepthStencilState.StencilDetphBufferFail = this.StencilDetphBufferFail; device._lastDepthStencilState.StencilPass = this.StencilPass; } } device._lastDepthStencilState.TwoSidedStencilMode = this.TwoSidedStencilMode; }
/// <summary> /// /// </summary> /// <param name="applyShaders"></param> internal void PlatformApplyState(bool applyShaders) { if (_scissorRectangleDirty) { var scissorRect = _scissorRectangle; if (!IsRenderTargetBound) { scissorRect.Y = _viewport.Height - scissorRect.Y - scissorRect.Height; } GL.Scissor(scissorRect.X, scissorRect.Y, scissorRect.Width, scissorRect.Height); GraphicsExtensions.CheckGLError(); _scissorRectangleDirty = false; } if (!applyShaders) { return; } if (_indexBufferDirty) { if (_indexBuffer != null) { GL.BindBuffer(BufferTarget.ElementArrayBuffer, _indexBuffer.ibo); GraphicsExtensions.CheckGLError(); } _indexBufferDirty = false; } if (_vertexBuffersDirty) { if (_vertexBuffers.Count > 0) { GL.BindBuffer(BufferTarget.ArrayBuffer, _vertexBuffers.Get(0).VertexBuffer.vbo); GraphicsExtensions.CheckGLError(); } _vertexBuffersDirty = false; } if (_vertexShader == null) { throw new InvalidOperationException("A Vertex Shader Must Be Set!"); } if (_pixelShader == null) { throw new InvalidOperationException("A Pixel Shader Must Be Set!"); } if (_vertexShaderDirty || _pixelShaderDirty) { ActivateShaderProgram(); if (_vertexShaderDirty) { unchecked { _graphicsMetrics._vertexShaderCount++; } } if (_pixelShaderDirty) { unchecked { _graphicsMetrics._pixelShaderCount++; } } _vertexShaderDirty = _pixelShaderDirty = false; } _vertexConstantBuffers.SetConstantBuffers(this, _shaderProgram); _pixelConstantBuffers.SetConstantBuffers(this, _shaderProgram); Textures.SetTextures(this); SamplerStates.PlatformSetSamplers(this); }
internal virtual void GenerateMipmap(int target) { GL.GenerateMipmap((TextureTarget)target); GraphicsExtensions.CheckGLError(); }
/// <summary> /// /// </summary> /// <param name="attachement"></param> /// <param name="renderbuffer"></param> /// <param name="level"></param> internal virtual void FramebufferRenderbuffer(int attachement, int renderbuffer, int level = 0) { GL.FramebufferRenderbuffer(FramebufferTarget.Framebuffer, (FramebufferSlot)attachement, RenderbufferTarget.Renderbuffer, renderbuffer); GraphicsExtensions.CheckGLError(); }
internal virtual void DeleteRenderbuffer(int renderbuffer) { GL.DeleteRenderbuffers(1, ref renderbuffer); GraphicsExtensions.CheckGLError(); }
internal virtual void BindRenderbuffer(int renderbuffer) { GL.BindRenderbuffer(RenderbufferTarget.Renderbuffer, renderbuffer); GraphicsExtensions.CheckGLError(); }
internal virtual void DeleteFramebuffer(int framebuffer) { GL.DeleteFramebuffers(1, ref framebuffer); GraphicsExtensions.CheckGLError(); }
internal virtual void BindReadFramebuffer(int readFramebuffer) { GL.BindFramebuffer((FramebufferTarget)AllReadFramebuffer, readFramebuffer); GraphicsExtensions.CheckGLError(); }
internal virtual void BlitFramebuffer(int iColorAttachment, int width, int height) { this.GLBlitFramebuffer(0, 0, width, height, 0, 0, width, height, ClearBufferMask.ColorBufferBit, TextureMagFilter.Nearest); GraphicsExtensions.CheckGLError(); }
/// <summary> /// /// </summary> private void PlatformResolveRenderTargets() { if (_currentRenderTargetCount == 0) { return; } var renderTargetBinding = this._currentRenderTargetBindings[0]; var renderTarget = renderTargetBinding.RenderTarget as IRenderTarget; if (renderTarget.MultiSampleCount > 0 && this.framebufferHelper.SupportsBlitFramebuffer) { var glResolveFramebuffer = 0; if (!this.glResolveFramebuffeers.TryGetValue(this._currentRenderTargetBindings, out glResolveFramebuffer)) { this.framebufferHelper.GenFramebuffer(out glResolveFramebuffer); this.framebufferHelper.BindFramebuffer(glResolveFramebuffer); for (var i = 0; i < this._currentRenderTargetCount; i++) { this.framebufferHelper.FramebufferTexture2D((int)(FramebufferAttachment.ColorAttachment0 + i), (int)renderTarget.GetFramebufferTarget(renderTargetBinding), renderTarget.GLTexture); } this.glResolveFramebuffeers.Add((RenderTargetBinding[])this._currentRenderTargetBindings.Clone(), glResolveFramebuffer); } else { this.framebufferHelper.BindFramebuffer(glResolveFramebuffer); } if (this._lastRasterizerState.ScissorTestEnable) { GL.Disable(EnableCap.ScissorTest); GraphicsExtensions.CheckGLError(); } var glFramebuffer = this.glFramebuffers[this._currentRenderTargetBindings]; this.framebufferHelper.BindReadFramebuffer(glFramebuffer); for (var i = 0; i < this._currentRenderTargetCount; i++) { renderTargetBinding = this._currentRenderTargetBindings[i]; renderTarget = renderTargetBinding.RenderTarget as IRenderTarget; this.framebufferHelper.BlitFramebuffer(i, renderTarget.Width, renderTarget.Height); } if (renderTarget.RenderTargetUsage == RenderTargetUsage.DiscardContents && this.framebufferHelper.SupportsInvalidateFramebuffer) { this.framebufferHelper.InvalidateReadFramebuffer(); } if (this._lastRasterizerState.ScissorTestEnable) { GL.Enable(EnableCap.ScissorTest); GraphicsExtensions.CheckGLError(); } } for (var i = 0; i < _currentRenderTargetCount; i++) { renderTargetBinding = _currentRenderTargetBindings[i]; renderTarget = renderTargetBinding.RenderTarget as IRenderTarget; if (renderTarget.LevelCount > 1) { GL.BindTexture(renderTarget.GLTarget, renderTarget.GLTexture); GraphicsExtensions.CheckGLError(); this.framebufferHelper.GenerateMipmap((int)renderTarget.GLTarget); } } }