private Metadata RequestMetadataInner(string path, bool async) { //System.Diagnostics.Debug.WriteLine("Loading metadata \"" + path + "\"..."); #if UNCOMPRESSED_CONTENT string pathAbsolute = PathOp.Combine(DualityApp.DataDirectory, "Metadata", path + ".res"); #else string pathAbsolute = PathOp.Combine(DualityApp.DataDirectory, "Main.dz", "Metadata", path + ".res"); #endif MetadataJson json; using (Stream s = FileOp.Open(pathAbsolute, FileAccessMode.Read)) { lock (jsonParser) { json = jsonParser.Parse<MetadataJson>(s); } } Metadata metadata = new Metadata(); metadata.Referenced = true; metadata.AsyncFinalizingRequired = async; // Pre-load graphics if (json.Animations != null) { metadata.Graphics = new Dictionary<string, GraphicResource>(); foreach (KeyValuePair<string, MetadataJson.AnimationsSection> g in json.Animations) { if (g.Value.Path == null) { // No path provided, skip resource... continue; } #if !THROW_ON_MISSING_RESOURCES try { #endif bool isIndexed = (g.Value.Flags & 0x02) != 0x00; ColorRgba color; if (g.Value.ShaderColor == null || g.Value.ShaderColor.Count < 4) { color = (isIndexed ? new ColorRgba(0, 255) : ColorRgba.White); } else { color = new ColorRgba((byte)g.Value.ShaderColor[0], (byte)g.Value.ShaderColor[1], (byte)g.Value.ShaderColor[2], (byte)g.Value.ShaderColor[3]); } GenericGraphicResource resBase = RequestGraphicResource(g.Value.Path, async); // Create copy of generic resource GraphicResource res; if (async) { res = GraphicResource.From(resBase, g.Value.Shader, color, isIndexed); } else { ContentRef<DrawTechnique> drawTechnique; if (g.Value.Shader == null) { drawTechnique = (isIndexed ? paletteNormal : basicNormal); } else { drawTechnique = RequestShader(g.Value.Shader); } res = GraphicResource.From(resBase, drawTechnique, color, isIndexed, paletteTexture); } res.FrameOffset = g.Value.FrameOffset; string raw1, raw2; int raw3; if ((raw1 = g.Value.FrameCount as string) != null && int.TryParse(raw1, out raw3)) { res.FrameCount = raw3; } else { res.FrameCount -= res.FrameOffset; } if ((raw2 = g.Value.FrameRate as string) != null && int.TryParse(raw2, out raw3)) { res.FrameDuration = (raw3 <= 0 ? -1 : (1f / raw3) * 5); // ToDo: I don't know... } res.OnlyOnce = (g.Value.Flags & 0x01) != 0x00; if (g.Value.States != null) { res.State = new HashSet<AnimState>(); for (int i = 0; i < g.Value.States.Count; i++) { res.State.Add((AnimState)g.Value.States[i]); } } metadata.Graphics[g.Key] = res; #if !THROW_ON_MISSING_RESOURCES } catch (Exception ex) { #if !SERVER Log.Write(LogType.Warning, "Can't load animation \"" + g.Key + "\" from metadata \"" + path + "\": " + ex.Message); #endif } #endif } } #if !DISABLE_SOUND // Pre-load sounds if (json.Sounds != null) { metadata.Sounds = new Dictionary<string, SoundResource>(); foreach (var sound in json.Sounds) { if (sound.Value.Paths == null || sound.Value.Paths.Count == 0) { // No path provided, skip resource... continue; } #if !THROW_ON_MISSING_RESOURCES try { #endif IList<string> filenames = sound.Value.Paths; ContentRef<AudioData>[] data = new ContentRef<AudioData>[filenames.Count]; for (int i = 0; i < data.Length; i++) { #if UNCOMPRESSED_CONTENT using (Stream s = FileOp.Open(PathOp.Combine(DualityApp.DataDirectory, "Animations", filenames[i]), FileAccessMode.Read)) #else using (Stream s = FileOp.Open(PathOp.Combine(DualityApp.DataDirectory, "Main.dz", "Animations", filenames[i]), FileAccessMode.Read)) #endif { data[i] = new AudioData(s); } } SoundResource resource = new SoundResource(); resource.Sound = new Sound(data); metadata.Sounds[sound.Key] = resource; #if !THROW_ON_MISSING_RESOURCES } catch (Exception ex) { #if !SERVER Log.Write(LogType.Warning, "Can't load sound \"" + sound.Key + "\" from metadata \"" + path + "\": " + ex.Message); #endif } #endif } } #endif // Bounding Box if (json.BoundingBox != null && json.BoundingBox.Count == 2) { metadata.BoundingBox = new Point2(json.BoundingBox[0], json.BoundingBox[1]); } cachedMetadata[path] = metadata; // Request children if (json.Preload != null) { for (int i = 0; i < json.Preload.Count; i++) { PreloadAsync(json.Preload[i]); } } return metadata; }
public GenericGraphicResource RequestGraphicResource(string path, bool async = false) { GenericGraphicResource resource; if (!cachedGraphics.TryGetValue(path, out resource)) { #if UNCOMPRESSED_CONTENT string pathAbsolute = PathOp.Combine(DualityApp.DataDirectory, "Animations", path); #else string pathAbsolute = PathOp.Combine(DualityApp.DataDirectory, "Main.dz", "Animations", path); #endif SpriteJson json; using (Stream s = FileOp.Open(pathAbsolute + ".res", FileAccessMode.Read)) { lock (jsonParser) { json = jsonParser.Parse<SpriteJson>(s); } } resource = new GenericGraphicResource { FrameDimensions = new Point2(json.FrameSize[0], json.FrameSize[1]), FrameConfiguration = new Point2(json.FrameConfiguration[0], json.FrameConfiguration[1]), FrameDuration = (json.FrameRate <= 0 ? -1 : (1f / json.FrameRate) * 5), FrameCount = json.FrameCount }; if (json.Hotspot != null) { resource.Hotspot = new Point2(json.Hotspot[0], json.Hotspot[1]); } if (json.Coldspot != null) { resource.Coldspot = new Point2(json.Coldspot[0], json.Coldspot[1]); resource.HasColdspot = true; } if (json.Gunspot != null) { resource.Gunspot = new Point2(json.Gunspot[0], json.Gunspot[1]); } PixelData pixelData; using (Stream s = FileOp.Open(pathAbsolute, FileAccessMode.Read)) { pixelData = new Png(s).GetPixelData(); } // Use external palette if ((json.Flags & 0x01) != 0x00) { ColorRgba[] palette = paletteTexture.Res.BasePixmap.Res.MainLayer.Data; ColorRgba[] data = pixelData.Data; #if !DISABLE_ASYNC Parallel.ForEach(Partitioner.Create(0, data.Length), range => { for (int i = range.Item1; i < range.Item2; i++) { #else for (int i = 0; i < data.Length; i++) { #endif int colorIdx = data[i].R; data[i] = palette[colorIdx].WithAlpha(palette[colorIdx].A * data[i].A / (255f * 255f)); // ToDo: Pinball sprites have strange palette (1-3 indices down), CandionV looks bad, other levels look different } #if !DISABLE_ASYNC }); #endif } bool linearSampling = (json.Flags & 0x02) != 0x00; Pixmap map = new Pixmap(pixelData); map.GenerateAnimAtlas(resource.FrameConfiguration.X, resource.FrameConfiguration.Y, 0); if (async) { GenericGraphicResourceAsyncFinalize asyncFinalize = new GenericGraphicResourceAsyncFinalize(); asyncFinalize.TextureMap = map; #if !DISABLE_NORMAL_MAPPING string filenameNormal = pathAbsolute.Replace(".png", ".n.png"); if (FileOp.Exists(filenameNormal)) { using (Stream s = FileOp.Open(filenameNormal, FileAccessMode.Read)) { asyncFinalize.TextureNormalMap = new Pixmap(new Png(s).GetPixelData()); } } else { resource.TextureNormal = defaultNormalMap; } #else resource.TextureNormal = defaultNormalMap; #endif asyncFinalize.LinearSampling = linearSampling; resource.AsyncFinalize = asyncFinalize; } else { TextureMagFilter magFilter; TextureMinFilter minFilter; if (linearSampling) { magFilter = TextureMagFilter.Linear; minFilter = TextureMinFilter.LinearMipmapLinear; } else { magFilter = TextureMagFilter.Nearest; minFilter = TextureMinFilter.Nearest; } resource.Texture = new Texture(map, TextureSizeMode.NonPowerOfTwo, magFilter, minFilter, json.TextureWrap, json.TextureWrap); #if !DISABLE_NORMAL_MAPPING string filenameNormal = pathAbsolute.Replace(".png", ".n.png"); if (FileOp.Exists(filenameNormal)) { using (Stream s = FileOp.Open(filenameNormal, FileAccessMode.Read)) { pixelData = new Png(s).GetPixelData(); } resource.TextureNormal = new Texture(new Pixmap(pixelData), TextureSizeMode.NonPowerOfTwo, magFilter, minFilter, json.TextureWrap, json.TextureWrap); resource.TextureNormal.Res.DetachSource(); } else { resource.TextureNormal = defaultNormalMap; } #else resource.TextureNormal = defaultNormalMap; #endif } cachedGraphics[path] = resource; } resource.Referenced = true; return resource; }
private void FinalizeAsyncLoadedResources(Metadata metadata) { if (metadata.Graphics != null) { foreach (var pair in metadata.Graphics) { GraphicResource res = pair.Value; GenericGraphicResource resBase = res.Base; if (resBase.AsyncFinalize != null) { TextureMagFilter magFilter; TextureMinFilter minFilter; if (resBase.AsyncFinalize.LinearSampling) { magFilter = TextureMagFilter.Linear; minFilter = TextureMinFilter.LinearMipmapLinear; } else { magFilter = TextureMagFilter.Nearest; minFilter = TextureMinFilter.Nearest; } resBase.Texture = new Texture(resBase.AsyncFinalize.TextureMap, TextureSizeMode.NonPowerOfTwo, magFilter, minFilter, resBase.AsyncFinalize.TextureWrap, resBase.AsyncFinalize.TextureWrap); if (resBase.AsyncFinalize.TextureNormalMap != null) { resBase.TextureNormal = new Texture(resBase.AsyncFinalize.TextureNormalMap, TextureSizeMode.NonPowerOfTwo, magFilter, minFilter, resBase.AsyncFinalize.TextureWrap, resBase.AsyncFinalize.TextureWrap); } resBase.AsyncFinalize = null; } if (res.AsyncFinalize != null) { ContentRef <DrawTechnique> drawTechnique; if (res.AsyncFinalize.Shader == null) { drawTechnique = (res.AsyncFinalize.BindPaletteToMaterial ? paletteNormal : basicNormal); } else { drawTechnique = RequestShader(res.AsyncFinalize.Shader); } Material material = new Material(drawTechnique, res.AsyncFinalize.Color); material.SetTexture("mainTex", resBase.Texture); if (resBase.TextureNormal != null) { material.SetTexture("normalTex", resBase.TextureNormal); } if (res.AsyncFinalize.BindPaletteToMaterial) { material.SetTexture("paletteTex", paletteTexture); } res.Material = material; res.AsyncFinalize = null; } } } }