A game framework written with osu! in mind.
at master 127 lines 5.0 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.Primitives; 6using osuTK; 7using osu.Framework.Graphics.Colour; 8using osu.Framework.Graphics.OpenGL.Vertices; 9using osu.Framework.Graphics.Textures; 10using osuTK.Graphics.ES30; 11 12namespace osu.Framework.Graphics.OpenGL.Textures 13{ 14 internal class TextureGLSub : TextureGL 15 { 16 private readonly TextureGL parent; 17 private RectangleI bounds; 18 19 public override RectangleI Bounds => bounds; 20 21 public override TextureGL Native => parent.Native; 22 23 public override int TextureId => parent.TextureId; 24 public override bool Loaded => parent.Loaded; 25 26 internal override bool IsQueuedForUpload 27 { 28 get => parent.IsQueuedForUpload; 29 set => parent.IsQueuedForUpload = value; 30 } 31 32 public TextureGLSub(RectangleI bounds, TextureGL parent, WrapMode wrapModeS = WrapMode.None, WrapMode wrapModeT = WrapMode.None) 33 : base(wrapModeS, wrapModeT) 34 { 35 // If GLWrapper is not initialized at this point, it means we do not have OpenGL available 36 // and thus will never draw anything. In this case it is fine if the parent texture is null. 37 if (GLWrapper.IsInitialized && parent == null) 38 throw new InvalidOperationException("May not construct a subtexture without a parent texture to refer to."); 39 40 this.bounds = bounds; 41 this.parent = parent; 42 } 43 44 public override int Height 45 { 46 get => bounds.Height; 47 set => bounds.Height = value; 48 } 49 50 public override int Width 51 { 52 get => bounds.Width; 53 set => bounds.Width = value; 54 } 55 56 private RectangleF boundsInParent(RectangleF? textureRect) 57 { 58 RectangleF actualBounds = bounds; 59 60 if (textureRect.HasValue) 61 { 62 RectangleF localBounds = textureRect.Value; 63 actualBounds.X += localBounds.X; 64 actualBounds.Y += localBounds.Y; 65 actualBounds.Width = localBounds.Width; 66 actualBounds.Height = localBounds.Height; 67 } 68 69 return actualBounds; 70 } 71 72 public override RectangleF GetTextureRect(RectangleF? textureRect) => parent.GetTextureRect(boundsInParent(textureRect)); 73 74 internal override void DrawTriangle(Triangle vertexTriangle, ColourInfo drawColour, RectangleF? textureRect = null, Action<TexturedVertex2D> vertexAction = null, 75 Vector2? inflationPercentage = null, RectangleF? textureCoords = null) 76 { 77 parent.DrawTriangle(vertexTriangle, drawColour, boundsInParent(textureRect), vertexAction, inflationPercentage, boundsInParent(textureCoords)); 78 } 79 80 internal override void DrawQuad(Quad vertexQuad, ColourInfo drawColour, RectangleF? textureRect = null, Action<TexturedVertex2D> vertexAction = null, Vector2? inflationPercentage = null, 81 Vector2? blendRangeOverride = null, RectangleF? textureCoords = null) 82 { 83 parent.DrawQuad(vertexQuad, drawColour, boundsInParent(textureRect), vertexAction, inflationPercentage: inflationPercentage, blendRangeOverride: blendRangeOverride, boundsInParent(textureCoords)); 84 } 85 86 internal override bool Bind(TextureUnit unit, WrapMode wrapModeS, WrapMode wrapModeT) 87 { 88 if (!Available) 89 throw new ObjectDisposedException(ToString(), "Can not bind disposed sub textures."); 90 91 Upload(); 92 93 return parent.Bind(unit, wrapModeS, wrapModeT); 94 } 95 96 internal override bool Upload() => false; 97 98 internal override void FlushUploads() 99 { 100 } 101 102 internal override void SetData(ITextureUpload upload, WrapMode wrapModeS, WrapMode wrapModeT, Opacity? uploadOpacity) 103 { 104 if (upload.Bounds.Width > bounds.Width || upload.Bounds.Height > bounds.Height) 105 { 106 throw new ArgumentOutOfRangeException( 107 nameof(upload), 108 $"Texture is too small to fit the requested upload. Texture size is {bounds.Width} x {bounds.Height}, upload size is {upload.Bounds.Width} x {upload.Bounds.Height}."); 109 } 110 111 if (upload.Bounds.IsEmpty) 112 upload.Bounds = bounds; 113 else 114 { 115 var adjustedBounds = upload.Bounds; 116 117 adjustedBounds.X += bounds.X; 118 adjustedBounds.Y += bounds.Y; 119 120 upload.Bounds = adjustedBounds; 121 } 122 123 UpdateOpacity(upload, ref uploadOpacity); 124 parent?.SetData(upload, wrapModeS, wrapModeT, uploadOpacity); 125 } 126 } 127}