protected override void DoUpload(ITextureUpload upload, IntPtr dataPointer) { if (!(upload is VideoTextureUpload videoUpload)) { return; } // Do we need to generate a new texture? if (textureIds == null) { Debug.Assert(memoryLease == null); memoryLease = NativeMemoryTracker.AddMemory(this, Width * Height * 3 / 2); textureIds = new int[3]; GL.GenTextures(textureIds.Length, textureIds); for (int i = 0; i < textureIds.Length; i++) { GLWrapper.BindTexture(textureIds[i]); if (i == 0) { int width = videoUpload.Frame->width; int height = videoUpload.Frame->height; GL.TexImage2D(TextureTarget2d.Texture2D, 0, TextureComponentCount.R8, width, height, 0, PixelFormat.Red, PixelType.UnsignedByte, IntPtr.Zero); textureSize += width * height; } else { int width = (videoUpload.Frame->width + 1) / 2; int height = (videoUpload.Frame->height + 1) / 2; GL.TexImage2D(TextureTarget2d.Texture2D, 0, TextureComponentCount.R8, width, height, 0, PixelFormat.Red, PixelType.UnsignedByte, IntPtr.Zero); textureSize += width * height; } GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMinFilter, (int)All.Linear); GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMagFilter, (int)All.Linear); GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapS, (int)TextureWrapMode.ClampToEdge); GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapT, (int)TextureWrapMode.ClampToEdge); } } for (int i = 0; i < textureIds.Length; i++) { GLWrapper.BindTexture(textureIds[i]); GL.PixelStore(PixelStoreParameter.UnpackRowLength, videoUpload.Frame->linesize[(uint)i]); GL.TexSubImage2D(TextureTarget2d.Texture2D, 0, 0, 0, videoUpload.Frame->width / (i > 0 ? 2 : 1), videoUpload.Frame->height / (i > 0 ? 2 : 1), PixelFormat.Red, PixelType.UnsignedByte, (IntPtr)videoUpload.Frame->data[(uint)i]); } GL.PixelStore(PixelStoreParameter.UnpackRowLength, 0); UploadComplete = true; }
public override bool Bind() { if (IsDisposed) { throw new ObjectDisposedException(ToString(), "Can not bind a disposed texture."); } Upload(); if (textureId <= 0) { return(false); } if (IsTransparent) { return(false); } GLWrapper.BindTexture(this); if (internalWrapMode != WrapMode) { updateWrapMode(); } return(true); }
public override bool Bind() { Debug.Assert(!isDisposed); Upload(); if (textureId <= 0) { return(false); } if (IsTransparent) { return(false); } GLWrapper.BindTexture(this); if (internalWrapMode != WrapMode) { updateWrapMode(); } return(true); }
internal override bool Bind(TextureUnit unit, WrapMode wrapModeS, WrapMode wrapModeT) { if (!Available) { throw new ObjectDisposedException(ToString(), "Can not bind a disposed texture."); } Upload(); if (textureIds == null) { return(false); } bool anyBound = false; for (int i = 0; i < textureIds.Length; i++) { anyBound |= GLWrapper.BindTexture(textureIds[i], unit + i, wrapModeS, wrapModeT); } if (anyBound) { BindCount++; } return(true); }
public void TestDrawTransparentTexture() { var pixels = new[] { new Pixel(), new Pixel(), new Pixel(), new Pixel() }; _window = new GameWindow { Width = 200, Height = 200 }; _window.RenderFrame += (caller, args) => { IGL gl = new GLWrapper(); gl.Viewport(0, 0, 200, 200); gl.ReadBuffer(ReadBufferMode.Front); gl.Enable(EnableCap.Texture2D); gl.Enable(EnableCap.Blend); gl.BlendFunc(BlendingFactorSrc.SrcAlpha, BlendingFactorDest.OneMinusSrcAlpha); gl.ClearColor(1.0f, 1.0f, 0.0f, 1.0f); int textureId = GL.GenTexture(); gl.BindTexture(TextureTarget.Texture2D, textureId); gl.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMinFilter, (int)TextureMinFilter.Nearest); gl.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMagFilter, (int)TextureMagFilter.Nearest); var bitmap = new Bitmap(@"..\..\Images\testtexture.png"); var data = bitmap.LockBits(new Rectangle(0, 0, bitmap.Width, bitmap.Height), ImageLockMode.ReadOnly, System.Drawing.Imaging.PixelFormat.Format32bppArgb); gl.TexImage2D(TextureTarget.Texture2D, 0, PixelInternalFormat.Rgba, data.Width, data.Height, 0, PixelFormat.Bgra, PixelType.UnsignedByte, data.Scan0); bitmap.UnlockBits(data); gl.Clear(ClearBufferMask.ColorBufferBit); gl.Begin(PrimitiveType.Quads); { gl.TexCoord2(0.0f, 0.0f); gl.Vertex2(-1.0f, -1.0f); gl.TexCoord2(1.0f, 0.0f); gl.Vertex2(1.0f, -1.0f); gl.TexCoord2(1.0f, 1.0f); gl.Vertex2(1.0f, 1.0f); gl.TexCoord2(0.0f, 1.0f); gl.Vertex2(-1.0f, 1.0f); } gl.End(); _window.SwapBuffers(); pixels[0].ReadBuffer(99, 99); pixels[1].ReadBuffer(99, 100); pixels[2].ReadBuffer(100, 100); pixels[3].ReadBuffer(100, 99); _window.Close(); }; _window.Run(); Assert.AreEqual(new Pixel(1.0f, 0.0f, 0.0f), pixels[0]); Assert.AreEqual(new Pixel(0.0f, 1.0f, 0.0f), pixels[1]); Assert.AreEqual(new Pixel(0.0f, 0.0f, 1.0f), pixels[2]); Assert.AreEqual(new Pixel(1.0f, 1.0f, 0.0f), pixels[3]); }
public override bool Bind(TextureUnit unit = TextureUnit.Texture0) { if (!Available) { throw new ObjectDisposedException(ToString(), "Can not bind a disposed texture."); } for (int i = 0; i < textureIds.Length; i++) { GLWrapper.BindTexture(textureIds[i], unit + i); } return(true); }
internal override bool Bind(TextureUnit unit, WrapMode wrapModeS, WrapMode wrapModeT) { if (!Available) { throw new ObjectDisposedException(ToString(), "Can not bind a disposed texture."); } for (int i = 0; i < textureIds.Length; i++) { GLWrapper.BindTexture(textureIds[i], unit + i, wrapModeS, wrapModeT); } return(true); }
public FrameBuffer(bool withTexture = true) { frameBuffer = GL.GenFramebuffer(); if (withTexture) { Texture = new TextureGLSingle(1, 1); Texture.SetData(new TextureUpload(0)); Texture.Upload(); Bind(); GL.FramebufferTexture2D(FramebufferTarget.Framebuffer, All.ColorAttachment0, TextureTarget2d.Texture2D, Texture.TextureId, 0); GLWrapper.BindTexture(0); Unbind(); } }
internal FrameBuffer(bool withTexture = true) { frameBuffer = GL.GenFramebuffer(); if (withTexture) { Texture = new TextureGLSingle(1, 1); Texture.SetData(new byte[0]); Texture.Upload(); Bind(); GL.FramebufferTexture2D(FramebufferTarget.Framebuffer, FramebufferSlot.ColorAttachment0, TextureTarget.Texture2D, Texture.TextureId, 0); GLWrapper.BindTexture(0); Unbind(); } }
public void Initialize(bool withTexture = true, All filteringMode = All.Linear) { frameBuffer = GL.GenFramebuffer(); if (withTexture) { Texture = new TextureGLSingle(1, 1, true, filteringMode); Texture.SetData(new TextureUpload(new byte[0])); Texture.Upload(); Bind(); GL.FramebufferTexture2D(FramebufferTarget.Framebuffer, FramebufferAttachment.ColorAttachment0, TextureTarget2d.Texture2D, Texture.TextureId, 0); GLWrapper.BindTexture(null); Unbind(); } IsInitialized = true; }
internal override bool Upload() { // We should never run raw OGL calls on another thread than the main thread due to race conditions. ThreadSafety.EnsureDrawThread(); if (IsDisposed) { throw new ObjectDisposedException(ToString(), "Can not upload data to a disposed texture."); } bool didUpload = false; while (uploadQueue.TryDequeue(out TextureUpload upload)) { IntPtr dataPointer; GCHandle?h0; if (upload.Data.Length == 0) { h0 = null; dataPointer = IntPtr.Zero; } else { h0 = GCHandle.Alloc(upload.Data, GCHandleType.Pinned); dataPointer = h0.Value.AddrOfPinnedObject(); didUpload = true; } try { // Do we need to generate a new texture? if (textureId <= 0 || internalWidth != width || internalHeight != height) { internalWidth = width; internalHeight = height; // We only need to generate a new texture if we don't have one already. Otherwise just re-use the current one. if (textureId <= 0) { int[] textures = new int[1]; GL.GenTextures(1, textures); textureId = textures[0]; GLWrapper.BindTexture(this); GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMinFilter, (int)(manualMipmaps ? filteringMode : (filteringMode == All.Linear ? All.LinearMipmapLinear : All.Nearest))); GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMagFilter, (int)filteringMode); // 33085 is GL_TEXTURE_MAX_LEVEL, which is not available within TextureParameterName. // It controls the amount of mipmap levels generated by GL.GenerateMipmap later on. GL.TexParameter(TextureTarget.Texture2D, (TextureParameterName)33085, MAX_MIPMAP_LEVELS); updateWrapMode(); } else { GLWrapper.BindTexture(this); } if (width == upload.Bounds.Width && height == upload.Bounds.Height || dataPointer == IntPtr.Zero) { GL.TexImage2D(TextureTarget2d.Texture2D, upload.Level, TextureComponentCount.Srgb8Alpha8, width, height, 0, upload.Format, PixelType.UnsignedByte, dataPointer); } else { initializeLevel(upload.Level, width, height); GL.TexSubImage2D(TextureTarget2d.Texture2D, upload.Level, upload.Bounds.X, upload.Bounds.Y, upload.Bounds.Width, upload.Bounds.Height, upload.Format, PixelType.UnsignedByte, dataPointer); } } // Just update content of the current texture else if (dataPointer != IntPtr.Zero) { GLWrapper.BindTexture(this); if (!manualMipmaps && upload.Level > 0) { //allocate mipmap levels int level = 1; int d = 2; while (width / d > 0) { initializeLevel(level, width / d, height / d); level++; d *= 2; } manualMipmaps = true; } int div = (int)Math.Pow(2, upload.Level); GL.TexSubImage2D(TextureTarget2d.Texture2D, upload.Level, upload.Bounds.X / div, upload.Bounds.Y / div, upload.Bounds.Width / div, upload.Bounds.Height / div, upload.Format, PixelType.UnsignedByte, dataPointer); } } finally { h0?.Free(); upload.Dispose(); } } if (didUpload && !manualMipmaps) { GL.Hint(HintTarget.GenerateMipmapHint, HintMode.Nicest); GL.GenerateMipmap(TextureTarget.Texture2D); } return(didUpload); }
public override bool Upload() { // We should never run raw OGL calls on another thread than the main thread due to race conditions. //Debug.Assert(Game.MainThread == Thread.CurrentThread); //todo: thread safety via GLWrapper. if (isDisposed) { return(false); } lock (this) { if (dataToBeUploaded == null) { return(false); } IntPtr dataPointer; GCHandle?h0; if (dataToBeUploaded.Length == 0) { h0 = null; dataPointer = IntPtr.Zero; } else { h0 = GCHandle.Alloc(dataToBeUploaded, GCHandleType.Pinned); dataPointer = h0.Value.AddrOfPinnedObject(); } try { // Do we need to generate a new texture? if (textureId <= 0 || internalWidth < width || internalHeight < height) { internalWidth = width; internalHeight = height; // We only need to generate a new texture if we don't have one already. Otherwise just re-use the current one. if (textureId <= 0) { int[] textures = new int[1]; GL.GenTextures(1, textures); textureId = textures[0]; GLWrapper.BindTexture(textureId); GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMinFilter, (int)All.LinearMipmapLinear); GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMagFilter, (int)All.LinearMipmapLinear); updateWrapMode(); } else { GLWrapper.BindTexture(textureId); } if (width == boundsToBeUploaded.Width && height == boundsToBeUploaded.Height || dataPointer == IntPtr.Zero) { GL.TexImage2D(TextureTarget2d.Texture2D, levelToBeUploaded, TextureComponentCount.Rgba, width, height, 0, formatToBeUploaded, PixelType.UnsignedByte, dataPointer); } else { if (transparentBlack.Length < width * height * 4) { transparentBlack = new byte[width * height * 4]; // Default value is 0, exactly what we need. } GCHandle h1 = GCHandle.Alloc(transparentBlack, GCHandleType.Pinned); GL.TexImage2D(TextureTarget2d.Texture2D, levelToBeUploaded, TextureComponentCount.Rgba, width, height, 0, formatToBeUploaded, PixelType.UnsignedByte, h1.AddrOfPinnedObject()); h1.Free(); GL.TexSubImage2D(TextureTarget2d.Texture2D, levelToBeUploaded, boundsToBeUploaded.X, boundsToBeUploaded.Y, boundsToBeUploaded.Width, boundsToBeUploaded.Height, formatToBeUploaded, PixelType.UnsignedByte, dataPointer); } GL.Hint(HintTarget.GenerateMipmapHint, HintMode.Nicest); GL.GenerateMipmap(TextureTarget.Texture2D); } // Just update content of the current texture else if (dataPointer != IntPtr.Zero) { GLWrapper.BindTexture(textureId); int div = (int)Math.Pow(2, levelToBeUploaded); GL.TexSubImage2D(TextureTarget2d.Texture2D, levelToBeUploaded, boundsToBeUploaded.X / div, boundsToBeUploaded.Y / div, boundsToBeUploaded.Width / div, boundsToBeUploaded.Height / div, formatToBeUploaded, PixelType.UnsignedByte, dataPointer); } return(true); } finally { if (h0.HasValue) { h0.Value.Free(); } if (dataToBeUploaded != null) { FreeBuffer(dataToBeUploaded); } dataToBeUploaded = null; } } }
protected override void DrawMesh(CubismDrawable drawable, Texture texture, FrameBuffer clippingMask, Matrix4 drawMatrix) { int offset = 1 + (clippingMask != null ? (drawable.ConstantFlags.HasFlag(ConstantDrawableFlags.IsInvertedMask) ? 2 : 1) : 0) + (UsePremultipliedAlpha ? 3 : 0); IShader shader; BlendingParameters blendingParameters; if (drawable.ConstantFlags.HasFlag(ConstantDrawableFlags.BlendMultiplicative)) { shader = shaders[offset]; blendingParameters = new BlendingParameters { Source = BlendingType.DstColor, Destination = BlendingType.OneMinusSrcAlpha, SourceAlpha = BlendingType.Zero, DestinationAlpha = BlendingType.One, }; } else if (drawable.ConstantFlags.HasFlag(ConstantDrawableFlags.BlendAdditive)) { shader = shaders[offset]; blendingParameters = new BlendingParameters { Source = BlendingType.One, Destination = BlendingType.One, SourceAlpha = BlendingType.Zero, DestinationAlpha = BlendingType.One, }; } else { shader = shaders[offset]; blendingParameters = new BlendingParameters { Source = BlendingType.One, Destination = BlendingType.OneMinusSrcAlpha, SourceAlpha = BlendingType.One, DestinationAlpha = BlendingType.OneMinusSrcAlpha, }; } GLWrapper.SetBlend(blendingParameters); shader.Bind(); if (clippingMask != null) { clippingMask.Texture.Bind(TextureUnit.Texture1); shader.GetUniform <int>("s_texture1").Value = 1; shader.GetUniform <Matrix4>("u_clipMatrix").Value = drawMatrix; shader.GetUniform <Vector4>("u_channelFlag").Value = new Vector4(1.0f, 0.0f, 0.0f, 0.0f); } else { GLWrapper.BindTexture(null, TextureUnit.Texture1); } texture.TextureGL.Bind(); shader.GetUniform <int>("s_texture0").Value = 0; shader.GetUniform <Matrix4>("u_matrix").Value = MvpMatrix; var color = new Vector4(Color.R, Color.G, Color.B, Color.A); color.W *= drawable.Opacity; if (UsePremultipliedAlpha) { color.X *= drawable.Opacity; color.Y *= drawable.Opacity; color.Z *= drawable.Opacity; } shader.GetUniform <Vector4>("u_baseColor").Value = color; GL.EnableVertexAttribArray(0); fixed(float *pinnedVertexBuffer = drawable.Vertices) GL.VertexAttribPointer(0, 2, VertexAttribPointerType.Float, false, sizeof(float) * 2, (IntPtr)pinnedVertexBuffer); GL.EnableVertexAttribArray(1); fixed(float *pinnedUVBuffer = drawable.TextureCoordinates) GL.VertexAttribPointer(1, 2, VertexAttribPointerType.Float, false, sizeof(float) * 2, (IntPtr)pinnedUVBuffer); fixed(short *pinnedIndexBuffer = drawable.Indices) GL.DrawElements(PrimitiveType.Triangles, drawable.Indices.Length, DrawElementsType.UnsignedShort, (IntPtr)pinnedIndexBuffer); shader.Unbind(); }
internal override bool Upload() { // We should never run raw OGL calls on another thread than the main thread due to race conditions. ThreadSafety.EnsureDrawThread(); if (isDisposed) { return(false); } IntPtr dataPointer; GCHandle? h0; TextureUpload upload; bool didUpload = false; while (uploadQueue.TryDequeue(out upload)) { if (upload.Data.Length == 0) { h0 = null; dataPointer = IntPtr.Zero; } else { h0 = GCHandle.Alloc(upload.Data, GCHandleType.Pinned); dataPointer = h0.Value.AddrOfPinnedObject(); didUpload = true; } try { // Do we need to generate a new texture? if (textureId <= 0 || internalWidth < width || internalHeight < height) { internalWidth = width; internalHeight = height; // We only need to generate a new texture if we don't have one already. Otherwise just re-use the current one. if (textureId <= 0) { int[] textures = new int[1]; GL.GenTextures(1, textures); textureId = textures[0]; GLWrapper.BindTexture(textureId); GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMinFilter, (int)All.LinearMipmapLinear); GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMagFilter, (int)All.Linear); updateWrapMode(); } else { GLWrapper.BindTexture(textureId); } if (width == upload.Bounds.Width && height == upload.Bounds.Height || dataPointer == IntPtr.Zero) { GL.TexImage2D(TextureTarget2d.Texture2D, upload.Level, TextureComponentCount.Rgba, width, height, 0, upload.Format, PixelType.UnsignedByte, dataPointer); } else { initializeLevel(upload.Level, width, height); GL.TexSubImage2D(TextureTarget2d.Texture2D, upload.Level, upload.Bounds.X, upload.Bounds.Y, upload.Bounds.Width, upload.Bounds.Height, upload.Format, PixelType.UnsignedByte, dataPointer); } } // Just update content of the current texture else if (dataPointer != IntPtr.Zero) { GLWrapper.BindTexture(textureId); if (!manualMipmaps && upload.Level > 0) { //allocate mipmap levels int level = 1; int d = 2; while (width / d > 0) { initializeLevel(level, width / d, height / d); level++; d *= 2; } manualMipmaps = true; } int div = (int)Math.Pow(2, upload.Level); GL.TexSubImage2D(TextureTarget2d.Texture2D, upload.Level, upload.Bounds.X / div, upload.Bounds.Y / div, upload.Bounds.Width / div, upload.Bounds.Height / div, upload.Format, PixelType.UnsignedByte, dataPointer); } } finally { h0?.Free(); upload?.Dispose(); } } if (didUpload && !manualMipmaps) { GL.Hint(HintTarget.GenerateMipmapHint, HintMode.Nicest); GL.GenerateMipmap(TextureTarget.Texture2D); } return(didUpload); }