/// <summary> /// Creates a texture from bytes laid out in BGRA format, row major. /// </summary> /// <param name="data">The raw bytes containing the texture in BGRA format, row major.</param> /// <param name="width">Width of the texture in pixels.</param> /// <param name="height">Height of the texture in pixels.</param> /// <returns>The created texture.</returns> public static pTexture FromRawBytes(byte[] data, int width, int height) { pTexture pt = new pTexture(width, height); pt.SetData(data); return(pt); }
internal static pTexture LoadFirst(string s, SkinSource source = SkinSource.All, bool dashSeparator = true) { pTexture sourceTex = Load(s, source); pTexture[] texArray = LoadAll(s, source, dashSeparator); pTexture alternateTex = texArray != null ? texArray[0] : null; return(textureFromMostSpecificSkin(sourceTex, alternateTex)); }
internal static pTexture LoadFirstAvailable(string[] names, SkinSource source = SkinSource.All) { pTexture t = null; foreach (string s in names) { if ((t = Load(s, source)) != null) { break; } } return(t); }
private static pTexture textureFromMostSpecificSkin(pTexture first, pTexture second) { if (first != null && ( second == null || first.Source == SkinSource.Beatmap || first.Source == SkinSource.Skin && second.Source != SkinSource.Beatmap || first.Source == SkinSource.Osu && second.Source != SkinSource.Beatmap && second.Source != SkinSource.Skin) ) { return(first); } return(second); }
/// <summary> /// Creates a texture from a bitmap. /// </summary> /// <param name="bitmap">The bitmap to create the texture from.</param> /// <returns>The created texture.</returns> public static pTexture FromBitmap(Bitmap bitmap, TextureAtlas atlas = null) { if (bitmap == null) { return(null); } int usableWidth = Math.Min(OsuGlControl.MaxTextureSize, bitmap.Width); int usableHeight = Math.Min(OsuGlControl.MaxTextureSize, bitmap.Height); pTexture tex = atlas == null ? new pTexture(usableWidth, usableHeight) : atlas.Add(usableWidth, usableHeight); tex.SetData(bitmap); return(tex); }
internal static void ClearBeatmapCache(bool force = false) { BeatmapCacheHoldReferences = force; if (BeatmapSpriteCache.Count == 0) { return; } //Avoid inter-thread access problems. pTexture[] cache = new pTexture[BeatmapSpriteCache.Count]; BeatmapSpriteCache.Values.CopyTo(cache, 0); foreach (pTexture t in cache) { if (t == null) { continue; } if (t.Disposable) { //textures marked as disposable will be cleaned up themselves, so we don't need to forcefully dispose. //this case is used in TransitionManager to allow extended lifetime on background sprites. continue; } t.Dispose(); } BeatmapSpriteCache.Clear(); AnimationCache.Clear(); BeatmapCacheReferences.Clear(); BeatmapCacheHoldReferences = false; LookupCache.Clear(); if (force) { ResetAtlases(BeatmapTextureAtlases); } }
internal static pTexture[] LoadAll(string s, SkinSource source = SkinSource.All, bool dashSeparator = true) { pTexture[] texArray; if (AnimationCache.TryGetValue(s, out texArray) && texArray[0].Source == source) { return(texArray); } int frameSuffixPosition = s.LastIndexOf('.'); string dash = dashSeparator ? @"-" : string.Empty; string frame0Name = frameSuffixPosition == -1 ? s + dash + 0 : s.Insert(frameSuffixPosition, dash + 0); pTexture animated = Load(frame0Name, source); pTexture sprite = Load(s, source); if (animated != null && animated == textureFromMostSpecificSkin(animated, sprite)) { List <pTexture> textures = new List <pTexture>(); for (int i = 1; animated != null; i++) { textures.Add(animated); string frameIName = frameSuffixPosition == -1 ? s + dash + i : s.Insert(frameSuffixPosition, dash + i); animated = Load(frameIName, animated.Source); } texArray = textures.ToArray(); AnimationCache[s] = texArray; return(texArray); } if (sprite != null) { texArray = new[] { sprite }; AnimationCache[s] = texArray; return(texArray); } return(null); }
internal static void Dereference(string filename) { if (BeatmapCacheHoldReferences) { return; } int referenceCount = 0; if (BeatmapCacheReferences.TryGetValue(filename, out referenceCount)) { if (referenceCount > 1) { //Still other references being held. BeatmapCacheReferences[filename]--; return; } } else { return; } //Doesn't exist in beatmapCache (is this right?) BeatmapCacheReferences.Remove(filename); if (!BeatmapSpriteCache.ContainsKey(filename)) { return; } pTexture tex = BeatmapSpriteCache[filename]; if (tex != null) { tex.Dispose(); BeatmapSpriteCache.Remove(filename); LookupCache.Clear(); } }
internal static void ReloadCache(Dictionary <string, pTexture> cache, bool force = false) { Dictionary <string, pTexture> oldCache = new Dictionary <string, pTexture>(cache); cache.Clear(); foreach (KeyValuePair <string, pTexture> s in oldCache) { if (s.Value == null) { cache[s.Key] = null; } else { if (s.Value.TextureGl != null) { s.Value.TextureGl.Dispose(); } pTexture newlyLoaded = Load(s.Key, s.Value.Source, s.Value.ContainingAtlas); if (newlyLoaded != null) { GC.SuppressFinalize(newlyLoaded); s.Value.TextureGl = newlyLoaded.TextureGl; s.Value.DpiScale = newlyLoaded.DpiScale; s.Value.IsDisposed = false; } else { s.Value.TextureGl = null; } cache[s.Key] = s.Value; LookupCache[s.Value.Source][s.Key] = s.Value; } } }
/// <summary> /// Creates a texture from a file containing a bitmap. /// </summary> /// <param name="filename">The file containing the texture data.</param> /// <returns>The created texture.</returns> public static pTexture FromFile(string filename, TextureAtlas atlas = null) { if (!File.Exists(filename)) { return(null); } try { using (Stream stream = new FileStream(filename, FileMode.Open, FileAccess.Read, FileShare.Read)) { pTexture t = FromStream(stream, atlas); if (t != null) { t.Filename = filename; } return(t); } } catch { return(null); } }
/// <summary> /// Read a pTexture from the ResourceStore (ouenresources project). /// </summary> public static pTexture FromResourceStore(string filename, TextureAtlas atlas = null) { pTexture tex = null; #if DEBUG tex = fromDebugLocations(filename); if (tex != null) { return(tex); } #endif //load using newer resources where available. if (GameBase.NewGraphicsAvailable) { tex = FromNewResourceStore(filename, atlas); if (tex != null) { tex.Filename = filename; return(tex); } } byte[] bytes = ResourcesStore.ResourceManager.GetObject(filename) as byte[]; if (bytes == null) { return(null); } using (Stream stream = new MemoryStream(bytes)) { using (HaxBinaryReader br = new HaxBinaryReader(stream)) { //XNA pipeline header crap. F**k it all. br.ReadBytes(10); int typeCount = br.Read7BitEncodedInt(); for (int i = 0; i < typeCount; i++) { br.ReadString(); br.ReadInt32(); } br.Read7BitEncodedInt(); br.Read7BitEncodedInt(); //And that's the header dealt with. br.ReadInt32(); int width = br.ReadInt32(); int height = br.ReadInt32(); tex = atlas == null ? new pTexture(width, height) : atlas.Add(width, height); tex.Filename = filename; int numberLevels = br.ReadInt32(); for (int i = 0; i < numberLevels; i++) { int count = br.ReadInt32(); byte[] data = br.ReadBytes(count); bgraToRgba(data, data.Length); tex.SetData(data, i, 0); } } } return(tex); }
static pTexture fromDebugLocations(string filename) { if (fswUi == null) { if (fswFailed) { return(null); } try { fswUi = new FileSystemWatcher(Path.Combine("..", "..", "..", "..", "osu!ui", "Resources")) { EnableRaisingEvents = true }; fswGameplay = new FileSystemWatcher(Path.Combine("..", "..", "..", "..", "osu!gameplay", "Resources")) { EnableRaisingEvents = true }; } catch { fswFailed = true; } } pTexture tex = null; bool x2 = GameBase.UseHighResolutionSprites; string suffix = GameBase.UseHighResolutionSprites ? @"@2x.png" : @".png"; string directFile = Path.Combine("..", "..", "..", "..", "osu!ui", "Resources", filename + suffix); tex = pTexture.FromFile(directFile); if (tex != null) { fswUi.Renamed += delegate(object sender, RenamedEventArgs e) { if (Path.GetFileName(directFile) != e.Name) { return; } while (true) { try { using (Stream stream = new FileStream(directFile, FileMode.Open, FileAccess.Read, FileShare.Read)) using (Bitmap b = (Bitmap)Image.FromStream(stream, false, false)) { tex.SetData(b); tex.UploadNextFrame(); } break; } catch { } } }; tex.Filename = directFile; tex.DpiScale = x2 ? 2 : 1; return(tex); } directFile = Path.Combine("..", "..", "..", "..", "osu!gameplay", "Resources", filename + suffix); tex = pTexture.FromFile(directFile); if (tex != null) { fswGameplay.Renamed += delegate(object sender, RenamedEventArgs e) { if (Path.GetFileName(directFile) != e.Name) { return; } while (true) { try { using (Stream stream = new FileStream(directFile, FileMode.Open, FileAccess.Read, FileShare.Read)) using (Bitmap b = (Bitmap)Image.FromStream(stream, false, false)) { tex.SetData(b); tex.UploadNextFrame(); } break; } catch { } } }; tex.Filename = directFile; tex.DpiScale = x2 ? 2 : 1; return(tex); } return(tex); }
public static pTexture FromNewResourceStore(string filename, TextureAtlas atlas = null) { bool highResolution = GameBase.UseHighResolutionSprites; if (highResolution) { filename += @"@2x"; } using (Bitmap b = osu_gameplay.ResourcesStore.ResourceManager.GetObject(filename) as Bitmap) if (b != null) { pTexture tex = FromBitmap(b, atlas); if (highResolution) { tex.DpiScale = 2; } return(tex); } //dll modification checks using (Bitmap b = osu_ui.ResourcesStore.ResourceManager.GetObject(filename) as Bitmap) if (b != null) { bool valid = true; switch (filename) { //case @"menu-osu": // valid &= b.GetPixel(320 / 2, 320 / 2) == System.Drawing.Color.FromArgb(255, 255, 190, 219); // valid &= b.GetPixel(220 / 2, 220 / 2) == System.Drawing.Color.FromArgb(255, 255, 199, 227); // valid &= b.GetPixel(420 / 2, 420 / 2) == System.Drawing.Color.FromArgb(255, 255, 245, 249); // break; //case @"menu-osu@2x": // valid &= b.GetPixel(320, 320) == System.Drawing.Color.FromArgb(255, 255, 190, 220); // valid &= b.GetPixel(220, 220) == System.Drawing.Color.FromArgb(255, 255, 199, 227); // valid &= b.GetPixel(420, 420) == System.Drawing.Color.FromArgb(255, 255, 245, 249); // break; //case @"menu-background": // valid &= b.GetPixel(0, 0) == System.Drawing.Color.FromArgb(243, 0, 206, 255); // valid &= b.GetPixel(400 / 2, 400 / 2) == System.Drawing.Color.FromArgb(255, 0, 165, 255); // valid &= b.GetPixel(1552 / 2, 1024 / 2) == System.Drawing.Color.FromArgb(255, 0, 144, 255); // break; //case @"menu-background@2x": // valid &= b.GetPixel(0, 0) == System.Drawing.Color.FromArgb(228, 1, 206, 255); // valid &= b.GetPixel(400, 400) == System.Drawing.Color.FromArgb(255, 0, 165, 255); // valid &= b.GetPixel(1552, 1024) == System.Drawing.Color.FromArgb(255, 0, 144, 255); // break; } if (!valid) { #if DEBUG throw new Exception(@"DLL modification checks need updating"); #else OsuMain.ExitImmediately(); #endif } pTexture tex = FromBitmap(b, atlas); if (highResolution) { tex.DpiScale = 2; } return(tex); } return(null); }
internal static pTexture Load(string name, SkinSource source = SkinSource.All, TextureAtlas atlas = null) { if (name == null) { return(null); } if (SkinManager.IgnoreBeatmapSkin && source != SkinSource.Beatmap) { source &= ~SkinSource.Beatmap; } if (source == SkinSource.All) { switch (GameBase.Mode) { case OsuModes.Play: case OsuModes.Edit: break; default: //As a default, don't load from the beatmap unless we are in play or edit mode. source &= ~SkinSource.Beatmap; break; } } pTexture tex = null; Dictionary <string, pTexture> dic = null; if (!LookupCache.TryGetValue(source, out dic)) { dic = LookupCache[source] = new Dictionary <string, pTexture>(); } if (dic.TryGetValue(name, out tex)) { return(tex); } try { //Check for beatmap-specific sprite availability Beatmap current = null; if ((source & SkinSource.Beatmap) > 0 && (current = BeatmapManager.Current) != null) { if (BeatmapSpriteCache.TryGetValue(name, out tex)) { //Cached sprite is available. //Note that we must check null *inside* this if block because a cached null means this source has no available file. //If we find a null, we don't want to enter the else block and check for a file every time, so we quietly ignore this source here. if (tex != null) { return(tex); } } else { string filename = name.IndexOf('.') < 0 ? name + @".png" : name; using (Stream stream = current.GetFileStream(filename)) { if (stream != null) { tex = pTexture.FromStream(stream, atlas); if (tex != null) { tex.Filename = filename; tex.AssetName = name; tex.Source = SkinSource.Beatmap; tex.UploadNextFrame(); } BeatmapSpriteCache[name] = tex; if (atlas != null) { BeatmapTextureAtlases.Add(atlas); } return(tex); } } BeatmapSpriteCache[name] = null; } } if ((source & SkinSource.Skin) > 0 && !SkinManager.IsDefault) { if (SkinSpriteCache.TryGetValue(name, out tex)) { //Cached sprite is available. //Note that we must check null *inside* this if block because a cached null means this source has no available file. //If we find a null, we don't want to enter the else block and check for a file every time, so we quietly ignore this source here. if (tex != null) { return(tex); } } else { string filename = Path.Combine(SkinManager.Current.FullPath, name.IndexOf('.') < 0 ? name + @".png" : name); string filename2x = filename.Insert(filename.LastIndexOf('.'), @"@2x"); if (GameBase.UseHighResolutionSprites && File.Exists(filename2x)) { tex = pTexture.FromFile(filename2x, atlas); SkinSpriteCache[name] = tex; if (atlas != null) { SkinTextureAtlases.Add(atlas); } if (tex != null) { tex.DpiScale = 2; tex.Source = SkinSource.Skin; tex.AssetName = name; tex.UploadNextFrame(); } return(tex); } if (File.Exists(filename)) { tex = pTexture.FromFile(filename, atlas); SkinSpriteCache[name] = tex; if (atlas != null) { SkinTextureAtlases.Add(atlas); } if (tex != null) { tex.Source = SkinSource.Skin; tex.AssetName = name; tex.UploadNextFrame(); } return(tex); } SkinSpriteCache[name] = null; } } if ((source & SkinSource.Osu) == 0) { return(null); } try { if (DefaultSpriteCache.TryGetValue(name, out tex)) { return(tex); } #if LOAD_LOCAL if ((tex = Load(name, SkinSource.Skin)) != null) { return(tex); } #endif name = GeneralHelper.PathSanitise(name); tex = name.IndexOf(Path.DirectorySeparatorChar) > 0 ? pTexture.FromFile(name, atlas) : pTexture.FromResourceStore(GeneralHelper.StripExtension(name), atlas); DefaultSpriteCache[name] = tex; if (atlas != null) { DefaultTextureAtlases.Add(atlas); } if (tex != null) { tex.Source = SkinSource.Osu; tex.AssetName = name; tex.UploadNextFrame(); } return(tex); } catch { return(null); } } finally { dic[name] = tex; } }