A game framework written with osu! in mind.
at master 224 lines 9.3 kB view raw
1// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence. 2// See the LICENCE file in the repository root for full licence text. 3 4using System; 5using osu.Framework.Graphics.Batches; 6using osu.Framework.Graphics.Primitives; 7using osuTK.Graphics.ES30; 8using osuTK; 9using osu.Framework.Graphics.Colour; 10using osu.Framework.Graphics.OpenGL.Vertices; 11using osu.Framework.Graphics.Textures; 12 13namespace osu.Framework.Graphics.OpenGL.Textures 14{ 15 public abstract class TextureGL : IDisposable 16 { 17 /// <summary> 18 /// The texture wrap mode in horizontal direction. 19 /// </summary> 20 public readonly WrapMode WrapModeS; 21 22 /// <summary> 23 /// The texture wrap mode in vertical direction. 24 /// </summary> 25 public readonly WrapMode WrapModeT; 26 27 protected TextureGL(WrapMode wrapModeS = WrapMode.None, WrapMode wrapModeT = WrapMode.None) 28 { 29 WrapModeS = wrapModeS; 30 WrapModeT = wrapModeT; 31 } 32 33 #region Disposal 34 35 internal virtual bool IsQueuedForUpload { get; set; } 36 37 /// <summary> 38 /// By default, texture uploads are queued for upload at the beginning of each frame, allowing loading them ahead of time. 39 /// When this is true, this will be bypassed and textures will only be uploaded on use. Should be set for every-frame texture uploads 40 /// to avoid overloading the global queue. 41 /// </summary> 42 public bool BypassTextureUploadQueueing; 43 44 /// <summary> 45 /// Whether this <see cref="TextureGL"/> can used for drawing. 46 /// </summary> 47 public bool Available { get; private set; } = true; 48 49 private bool isDisposed; 50 51 protected virtual void Dispose(bool isDisposing) => GLWrapper.ScheduleDisposal(() => Available = false); 52 53 public void Dispose() 54 { 55 if (isDisposed) 56 return; 57 58 isDisposed = true; 59 60 Dispose(true); 61 GC.SuppressFinalize(this); 62 } 63 64 #endregion 65 66 public abstract TextureGL Native { get; } 67 68 public abstract bool Loaded { get; } 69 70 public Opacity Opacity { get; protected set; } = Opacity.Mixed; 71 72 public abstract int TextureId { get; } 73 74 public abstract int Height { get; set; } 75 76 public abstract int Width { get; set; } 77 78 public abstract RectangleI Bounds { get; } 79 80 public Vector2 Size => new Vector2(Width, Height); 81 82 public abstract RectangleF GetTextureRect(RectangleF? textureRect); 83 84 /// <summary> 85 /// Draws a triangle to the screen. 86 /// </summary> 87 /// <param name="vertexTriangle">The triangle to draw.</param> 88 /// <param name="drawColour">The vertex colour.</param> 89 /// <param name="textureRect">The texture rectangle.</param> 90 /// <param name="vertexAction">An action that adds vertices to a <see cref="VertexBatch{T}"/>.</param> 91 /// <param name="inflationPercentage">The percentage amount that <paramref name="textureRect"/> should be inflated.</param> 92 /// <param name="textureCoords">The texture coordinates of the triangle's vertices (translated from the corresponding quad's rectangle).</param> 93 internal abstract void DrawTriangle(Triangle vertexTriangle, ColourInfo drawColour, RectangleF? textureRect = null, Action<TexturedVertex2D> vertexAction = null, 94 Vector2? inflationPercentage = null, RectangleF? textureCoords = null); 95 96 /// <summary> 97 /// Draws a quad to the screen. 98 /// </summary> 99 /// <param name="vertexQuad">The quad to draw.</param> 100 /// <param name="drawColour">The vertex colour.</param> 101 /// <param name="textureRect">The texture rectangle.</param> 102 /// <param name="vertexAction">An action that adds vertices to a <see cref="VertexBatch{T}"/>.</param> 103 /// <param name="inflationPercentage">The percentage amount that <paramref name="textureRect"/> should be inflated.</param> 104 /// <param name="blendRangeOverride">The range over which the edges of the <paramref name="textureRect"/> should be blended.</param> 105 /// <param name="textureCoords">The texture coordinates of the quad's vertices.</param> 106 internal abstract void DrawQuad(Quad vertexQuad, ColourInfo drawColour, RectangleF? textureRect = null, Action<TexturedVertex2D> vertexAction = null, Vector2? inflationPercentage = null, 107 Vector2? blendRangeOverride = null, RectangleF? textureCoords = null); 108 109 /// <summary> 110 /// Bind as active texture. 111 /// </summary> 112 /// <param name="unit">The texture unit to bind to. Defaults to Texture0.</param> 113 /// <returns>True if bind was successful.</returns> 114 public bool Bind(TextureUnit unit = TextureUnit.Texture0) => Bind(unit, WrapModeS, WrapModeT); 115 116 /// <summary> 117 /// Bind as active texture. 118 /// </summary> 119 /// <param name="unit">The texture unit to bind to.</param> 120 /// <param name="wrapModeS">The texture wrap mode in horizontal direction.</param> 121 /// <param name="wrapModeT">The texture wrap mode in vertical direction.</param> 122 /// <returns>True if bind was successful.</returns> 123 internal abstract bool Bind(TextureUnit unit, WrapMode wrapModeS, WrapMode wrapModeT); 124 125 /// <summary> 126 /// Uploads pending texture data to the GPU if it exists. 127 /// </summary> 128 /// <returns>Whether pending data existed and an upload has been performed.</returns> 129 internal abstract bool Upload(); 130 131 /// <summary> 132 /// Flush any unprocessed uploads without actually uploading. 133 /// </summary> 134 internal abstract void FlushUploads(); 135 136 /// <summary> 137 /// Sets the pixel data of this <see cref="TextureGL"/>. 138 /// </summary> 139 /// <param name="upload">The <see cref="ITextureUpload"/> containing the data.</param> 140 public void SetData(ITextureUpload upload) => SetData(upload, WrapModeS, WrapModeT, null); 141 142 /// <summary> 143 /// Sets the pixel data of this <see cref="TextureGLAtlas"/>. 144 /// </summary> 145 /// <param name="upload">The <see cref="ITextureUpload"/> containing the data.</param> 146 /// <param name="wrapModeS">The texture wrap mode in horizontal direction.</param> 147 /// <param name="wrapModeT">The texture wrap mode in vertical direction.</param> 148 /// <param name="uploadOpacity">Whether the upload is opaque, transparent, or a mix of both..</param> 149 internal abstract void SetData(ITextureUpload upload, WrapMode wrapModeS, WrapMode wrapModeT, Opacity? uploadOpacity); 150 151 protected static Opacity ComputeOpacity(ITextureUpload upload) 152 { 153 // TODO: Investigate performance issues and revert functionality once we are sure there is no overhead. 154 // see https://github.com/ppy/osu/issues/9307 155 return Opacity.Mixed; 156 157 // if (upload.Data.Length == 0) 158 // return Opacity.Transparent; 159 // 160 // bool isTransparent = true; 161 // bool isOpaque = true; 162 // 163 // for (int i = 0; i < upload.Data.Length; ++i) 164 // { 165 // isTransparent &= upload.Data[i].A == 0; 166 // isOpaque &= upload.Data[i].A == 255; 167 // 168 // if (!isTransparent && !isOpaque) 169 // return Opacity.Mixed; 170 // } 171 // 172 // if (isTransparent) 173 // return Opacity.Transparent; 174 // 175 // return Opacity.Opaque; 176 } 177 178 protected void UpdateOpacity(ITextureUpload upload, ref Opacity? uploadOpacity) 179 { 180 // Compute opacity if it doesn't have a value yet 181 uploadOpacity ??= ComputeOpacity(upload); 182 183 // Update the texture's opacity depending on the upload's opacity. 184 // If the upload covers the entire bounds of the texture, it fully 185 // determines the texture's opacity. Otherwise, it can only turn 186 // the texture's opacity into a mixed state (if it disagrees with 187 // the texture's existing opacity). 188 if (upload.Bounds == Bounds && upload.Level == 0) 189 Opacity = uploadOpacity.Value; 190 else if (uploadOpacity.Value != Opacity) 191 Opacity = Opacity.Mixed; 192 } 193 } 194 195 public enum WrapMode 196 { 197 /// <summary> 198 /// No wrapping. If the texture is part of an atlas, this may read outside the texture's bounds. 199 /// </summary> 200 None = 0, 201 202 /// <summary> 203 /// Clamps to the edge of the texture, repeating the edge to fill the remainder of the draw area. 204 /// </summary> 205 ClampToEdge = 1, 206 207 /// <summary> 208 /// Clamps to a transparent-black border around the texture, repeating the border to fill the remainder of the draw area. 209 /// </summary> 210 ClampToBorder = 2, 211 212 /// <summary> 213 /// Repeats the texture. 214 /// </summary> 215 Repeat = 3, 216 } 217 218 public enum Opacity 219 { 220 Opaque, 221 Mixed, 222 Transparent, 223 } 224}