Beispiel #1
0
        public new void DisposeBillboardBuffers()
        {
            if (!MainThreadHelper.IsMainThread && (
                    (billboardVertices != null && !billboardVertices.IsDisposed) ||
                    (billboardIndices != null && !billboardIndices.IsDisposed)
                    ))
            {
                // This is a disposal, there's no need to wait for this to be disposed,
                // let following reset calls realloc even before the olds get disposed.
                VertexBuffer billboardVerticesOld = billboardVertices;
                IndexBuffer  billboardIndicesOld  = billboardIndices;
                billboardVertices = null;
                billboardIndices  = null;
                MainThreadHelper.Do(() => {
                    if (billboardVerticesOld != null && !billboardVerticesOld.IsDisposed)
                    {
                        billboardVerticesOld.Dispose();
                    }
                    if (billboardIndicesOld != null && !billboardIndicesOld.IsDisposed)
                    {
                        billboardIndicesOld.Dispose();
                    }
                });
                return;
            }

            if (billboardVertices != null && !billboardVertices.IsDisposed)
            {
                billboardVertices.Dispose();
            }
            if (billboardIndices != null && !billboardIndices.IsDisposed)
            {
                billboardIndices.Dispose();
            }
        }
 public void Exit()
 {
     task = null;
     Lines.Clear();
     MainThreadHelper.Do(() => ((patch_OuiMainMenu)Overworld.GetUI <OuiMainMenu>())?.RebuildMainAndTitle());
     Audio.Play(SFX.ui_main_button_back);
     Overworld.Goto <OuiModOptions>();
 }
Beispiel #3
0
        internal bool Load(bool wait, Func <Texture2D> load)
        {
            if (LoadImmediately)
            {
                Texture_Unsafe?.Dispose();
                Texture_Unsafe = load();
                FreeFastTextureLoad();
                return(true);
            }

            // Let's queue a reload onto the main thread and call it a day.
            // Make sure to read the texture size immediately though!
            object queuedLoadLock;

            lock (queuedLoadLock = new object()) {
                _Texture_QueuedLoadLock = queuedLoadLock;

                Func <Texture2D> _load = load;
                load = () => {
                    Texture2D tex;
                    lock (queuedLoadLock) {
                        if (_Texture_QueuedLoadLock != queuedLoadLock)
                        {
                            _load = null;
                            FreeFastTextureLoad();
                            return(Texture_Unsafe);
                        }
                        // NOTE: If something dares to change texture info on the fly, GOOD LUCK.
                        Texture_Unsafe?.Dispose();
                        Texture_Unsafe = tex = _load();
                        FreeFastTextureLoad();
                        _Texture_QueuedLoadLock = null;
                    }
                    if (_Texture_UnloadAfterReload)
                    {
                        tex?.Dispose();
                        tex = Texture_Unsafe;
                        // ... can anything even swap the texture here?
                        Texture_Unsafe = null;
                        tex?.Dispose();
                        _Texture_UnloadAfterReload = false;
                    }
                    return(tex);
                };

                _Texture_QueuedLoad = !_Texture_FTLLoading?
                                      MainThreadHelper.GetForceQueue(load) :
                                          MainThreadHelper.Get(load);
            }

            if (wait || _Texture_Requesting)
            {
                _Texture_QueuedLoad.GetResult();
            }

            return(false);
        }
Beispiel #4
0
    public static void Init()
    {
        var obj = GameObject.Find("MainThreadHelper");

        if (obj == null)
        {
            helper = (new GameObject("MainThreadHelper")).AddComponent <MainThreadHelper>();
        }
    }
Beispiel #5
0
        internal override void Reload()
        {
            _Texture_Reloading = true;

            if (Metadata == null)
            {
                orig_Reload();
                _Texture_Reloading = false;
                return;
            }

            Unload();
            Texture = null;

            Stream stream = Metadata.Stream;

            if (stream != null)
            {
                bool premul = false; // Assume unpremultiplied by default.
                if (Metadata.TryGetMeta(out TextureMeta meta))
                {
                    premul = meta.Premultiplied;
                }

                using (stream) {
                    if (premul)
                    {
                        Texture = MainThreadHelper.Get(() => Texture2D.FromStream(Celeste.Celeste.Instance.GraphicsDevice, stream)).GetResult();
                    }
                    else
                    {
                        ContentExtensions.LoadTextureLazyPremultiply(Celeste.Celeste.Instance.GraphicsDevice, stream, out int w, out int h, out byte[] data);
                        Texture = MainThreadHelper.Get(() => {
                            Texture2D tex = new Texture2D(Celeste.Celeste.Instance.GraphicsDevice, w, h, false, SurfaceFormat.Color);
                            tex.SetData(data);
                            return(tex);
                        }).GetResult();
                    }
                }
            }
            else if (Fallback != null)
            {
                ((patch_VirtualTexture)(object)Fallback).Reload();
                Texture = Fallback.Texture;
            }

            if (Texture != null)
            {
                Width  = Texture.Width;
                Height = Texture.Height;
            }

            _Texture_Reloading = false;
        }
Beispiel #6
0
 public MainThreadHelper()
 {
     if (_instance == null)
     {
         _instance = this;
     }
     else
     {
         Debug.LogError("There should be only one instance");
     }
 }
Beispiel #7
0
        private void LoadThread()
        {
            MInput.Disabled        = true;
            MainThreadHelper.Boost = 25;
            Stopwatch timer = Stopwatch.StartNew();

            Audio.Init();
            // Original code loads audio banks here.
            Settings.Instance.ApplyVolumes();
            audioLoaded = true;
            Console.WriteLine(" - AUDIO LOAD: " + timer.ElapsedMilliseconds + "ms");
            timer.Stop();

            GFX.Load();
            MTN.Load();
            GFX.LoadData();
            MTN.LoadData();

            timer = Stopwatch.StartNew();
            Fonts.Prepare();
            Dialog.Load();
            Fonts.Load(Dialog.Languages["english"].FontFace);
            Fonts.Load(Dialog.Languages[Settings.Instance.Language].FontFace);
            dialogLoaded = true;
            Console.WriteLine(" - DIA/FONT LOAD: " + timer.ElapsedMilliseconds + "ms");
            timer.Stop();
            MInput.Disabled = false;

            timer = Stopwatch.StartNew();
            AreaData.Load();
            Console.WriteLine(" - LEVELS LOAD: " + timer.ElapsedMilliseconds + "ms");
            timer.Stop();

            timer = Stopwatch.StartNew();
            MainThreadHelper.Boost = 50;
            patch_VirtualTexture.WaitFinishFastTextureLoading();
            MainThreadHelper.Get(() => MainThreadHelper.Boost = 0).GetResult();
            // FIXME: There could be ongoing tasks which add to the main thread queue right here.
            Console.WriteLine(" - FASTTEXTURELOADING LOAD: " + timer.ElapsedMilliseconds + "ms");
            timer.Stop();

            Console.WriteLine("DONE LOADING (in " + Celeste.LoadTimer.ElapsedMilliseconds + "ms)");
            Celeste.LoadTimer.Stop();
            Celeste.LoadTimer = null;
            loaded            = true;
        }
    private void Awake()
    {
        Directory.CreateDirectory(performanceDataDir);
        if (finished)
        {
            return;
        }
        int numTests = Enum.GetNames(typeof(Tests)).Length;

        perfData = new PerfData[numTests];

        shader          = FindObjectOfType <PMBShader>().shaderRef;
        pmb             = new PMB(shader);
        globalStopwatch = Stopwatch.StartNew();

        helper = FindObjectOfType <MainThreadHelper>();

        Noise n = new PerlinNoise(42, 5f);

        UnityEngine.Debug.Log("Starting Task");
        Task.Factory.StartNew(() => {
            if (finished)
            {
                return;
            }
            var checkerboard = genericTest(Tests.Checkerboard, "checkerboard", 2, 5, (s, x, y, z) => (x + y + z) % 2);
            while (checkerboard.MoveNext())
            {
                ;
            }
            var empty = genericTest(Tests.Empty, "empty", 5, 6, (s, x, y, z) => 0);
            while (empty.MoveNext())
            {
                ;
            }
            var simpleNoise = genericTest(Tests.SimpleNoise, "simple-noise", 5, 5, (s, x, y, z) => n.Sample3D(x, y, z));
            while (simpleNoise.MoveNext())
            {
                ;
            }
            UnityEngine.Debug.Log("finish testing");
            finishTesting();
        });
    }
Beispiel #9
0
        internal override void Unload()
        {
            Texture2D tex = Texture_Unsafe;

            // Handle already queued loads appropriately.
            object queuedLoadLock = _Texture_QueuedLoadLock;

            if (queuedLoadLock != null)
            {
                bool gotLock = false;
                try {
                    Monitor.TryEnter(queuedLoadLock, ref gotLock);
                    if (gotLock)
                    {
                        if (_Texture_QueuedLoadLock != null)
                        {
                            // If we still can, cancel the queued load.
                            _Texture_QueuedLoadLock = null;
                        }
                    }
                    else
                    {
                        // Welp.
                        _Texture_UnloadAfterReload = true;
                        Monitor.TryEnter(queuedLoadLock, ref gotLock);
                        if (gotLock)
                        {
                            // It might be too late - let's unload ourselves.
                            _Texture_UnloadAfterReload = false;
                        }
                        else
                        {
                            // The loader will still handle the request.
                            return;
                        }
                    }
                } finally {
                    if (gotLock)
                    {
                        Monitor.Exit(queuedLoadLock);
                    }
                }

                if (!MainThreadHelper.IsMainThread)
                {
                    // Otherwise wait for it to get loaded. (Don't wait locked!)
                    while (!_Texture_QueuedLoad.IsValid)
                    {
                        Thread.Yield();
                    }
                    tex = _Texture_QueuedLoad.GetResult();
                }
            }

            Texture_Unsafe = null;
            if (tex == null || tex.IsDisposed)
            {
                return;
            }

            if (!(CoreModule.Settings.ThreadedGL ?? Everest.Flags.PreferThreadedGL) && !MainThreadHelper.IsMainThread)
            {
                MainThreadHelper.Do(() => tex.Dispose());
            }
            else
            {
                tex.Dispose();
            }
        }
Beispiel #10
0
        protected override void addOptionsToMenu(TextMenu menu)
        {
            // for now, display a "loading" message.
            TextMenu.Button loading = new TextMenu.Button(Dialog.Clean("MODOPTIONS_MODTOGGLE_LOADING"))
            {
                Disabled = true
            };
            menu.Add(loading);

            modLoadingTask = new Task(() => {
                // load all the mod yamls (that can take some time), update the progress every 500ms so that the text doesn't go crazy since it is centered.
                Stopwatch updateTimer = Stopwatch.StartNew();
                modYamls = LoadAllModYamls(progress => {
                    if (updateTimer.ElapsedMilliseconds > 500)
                    {
                        updateTimer.Restart();
                        loading.Label = $"{Dialog.Clean("MODOPTIONS_MODTOGGLE_LOADING")} ({(int) (progress * 100)}%)";
                    }
                });
                updateTimer.Stop();

                MainThreadHelper.Do(() => {
                    modToggles = new Dictionary <string, TextMenu.OnOff>();

                    // remove the "loading..." message
                    menu.Remove(loading);

                    // if there is a whitelist, warn the user that it will break those settings.
                    if (Everest.Loader.Whitelist != null)
                    {
                        menu.Add(restartMessage1 = new TextMenuExt.SubHeaderExt(Dialog.Clean("MODOPTIONS_MODTOGGLE_WHITELISTWARN"))
                        {
                            TextColor = Color.OrangeRed
                        });
                    }

                    // display the warning about blacklist.txt + restarting
                    menu.Add(restartMessage1 = new TextMenuExt.SubHeaderExt(Dialog.Clean("MODOPTIONS_MODTOGGLE_MESSAGE_1")));
                    menu.Add(restartMessage2 = new TextMenuExt.SubHeaderExt(Dialog.Clean("MODOPTIONS_MODTOGGLE_MESSAGE_2"))
                    {
                        HeightExtra = 0f
                    });
                    menu.Add(new TextMenuExt.SubHeaderExt(Dialog.Clean("MODOPTIONS_MODTOGGLE_MESSAGE_3"))
                    {
                        HeightExtra = 20f, TextColor = Color.Goldenrod
                    });

                    // reduce spacing between the whitelist warning and the blacklist overwrite warning
                    if (Everest.Loader.Whitelist != null)
                    {
                        restartMessage1.HeightExtra = 30f;
                    }

                    // "enable all" and "disable all" buttons
                    menu.Add(new TextMenu.Button(Dialog.Clean("MODOPTIONS_MODTOGGLE_ENABLEALL")).Pressed(() => {
                        foreach (TextMenu.OnOff toggle in modToggles.Values)
                        {
                            toggle.Index = 1;
                        }
                        blacklistedMods.Clear();
                        updateHighlightedMods();
                    }));
                    menu.Add(new TextMenu.Button(Dialog.Clean("MODOPTIONS_MODTOGGLE_DISABLEALL")).Pressed(() => {
                        blacklistedMods.Clear();
                        foreach (KeyValuePair <string, TextMenu.OnOff> toggle in modToggles)
                        {
                            toggle.Value.Index = 0;
                            blacklistedMods.Add(toggle.Key);
                        }
                        updateHighlightedMods();
                    }));

                    // "toggle dependencies automatically" button
                    TextMenu.Item toggleDependenciesButton;
                    menu.Add(toggleDependenciesButton = new TextMenu.OnOff(Dialog.Clean("MODOPTIONS_MODTOGGLE_TOGGLEDEPS"), true)
                                                        .Change(value => toggleDependencies = value));

                    toggleDependenciesButton.AddDescription(menu, Dialog.Clean("MODOPTIONS_MODTOGGLE_TOGGLEDEPS_MESSAGE2"));
                    toggleDependenciesButton.AddDescription(menu, Dialog.Clean("MODOPTIONS_MODTOGGLE_TOGGLEDEPS_MESSAGE1"));

                    // "cancel" button to leave the screen without saving
                    menu.Add(new TextMenu.Button(Dialog.Clean("MODOPTIONS_MODTOGGLE_CANCEL")).Pressed(() => {
                        blacklistedMods = blacklistedModsOriginal;
                        onBackPressed(Overworld);
                    }));

                    // reset the mods list
                    allMods         = new List <string>();
                    blacklistedMods = new HashSet <string>();

                    string[] files;
                    bool headerInserted;

                    // crawl directories
                    files = Directory.GetDirectories(Everest.Loader.PathMods);
                    Array.Sort(files, (a, b) => a.ToLowerInvariant().CompareTo(b.ToLowerInvariant()));
                    headerInserted = false;
                    for (int i = 0; i < files.Length; i++)
                    {
                        string file = Path.GetFileName(files[i]);
                        if (file != "Cache")
                        {
                            if (!headerInserted)
                            {
                                menu.Add(new patch_TextMenu.patch_SubHeader(Dialog.Clean("MODOPTIONS_MODTOGGLE_DIRECTORIES")));
                                headerInserted = true;
                            }
                            addFileToMenu(menu, file);
                        }
                    }

                    // crawl zips
                    files = Directory.GetFiles(Everest.Loader.PathMods);
                    Array.Sort(files, (a, b) => a.ToLowerInvariant().CompareTo(b.ToLowerInvariant()));
                    headerInserted = false;
                    for (int i = 0; i < files.Length; i++)
                    {
                        string file = Path.GetFileName(files[i]);
                        if (file.EndsWith(".zip"))
                        {
                            if (!headerInserted)
                            {
                                menu.Add(new patch_TextMenu.patch_SubHeader(Dialog.Clean("MODOPTIONS_MODTOGGLE_ZIPS")));
                                headerInserted = true;
                            }
                            addFileToMenu(menu, file);
                        }
                    }

                    // crawl map bins
                    files = Directory.GetFiles(Everest.Loader.PathMods);
                    Array.Sort(files, (a, b) => a.ToLowerInvariant().CompareTo(b.ToLowerInvariant()));
                    headerInserted = false;
                    for (int i = 0; i < files.Length; i++)
                    {
                        string file = Path.GetFileName(files[i]);
                        if (file.EndsWith(".bin"))
                        {
                            if (!headerInserted)
                            {
                                menu.Add(new patch_TextMenu.patch_SubHeader(Dialog.Clean("MODOPTIONS_MODTOGGLE_BINS")));
                                headerInserted = true;
                            }
                            addFileToMenu(menu, file);
                        }
                    }

                    // sort the mods list alphabetically, for output in the blacklist.txt file later.
                    allMods.Sort((a, b) => a.ToLowerInvariant().CompareTo(b.ToLowerInvariant()));

                    // adjust the mods' color if they are required dependencies for other mods
                    foreach (KeyValuePair <string, TextMenu.OnOff> toggle in modToggles)
                    {
                        if (modHasDependencies(toggle.Key))
                        {
                            ((patch_TextMenu.patch_Option <bool>)(object) toggle.Value).UnselectedColor = Color.Goldenrod;
                        }
                    }

                    // snap the menu so that it doesn't show a scroll up.
                    menu.Y = menu.ScrollTargetY;

                    // clone the list to be able to check if the list changed when leaving the menu.
                    blacklistedModsOriginal = new HashSet <string>(blacklistedMods);

                    // loading is done!
                    modLoadingTask = null;
                });
            });
            modLoadingTask.Start();
        }
Beispiel #11
0
        private bool ResetVertexBuffer()
        {
            // Checking for IsDisposed on other threads should be fine...
            if (Vertices != null && !Vertices.IsDisposed && !Vertices.GraphicsDevice.IsDisposed)
            {
                return(false);
            }

            // Handle already queued loads appropriately.
            object queuedLoadLock = _Vertices_QueuedLoadLock;

            if (queuedLoadLock != null)
            {
                lock (queuedLoadLock) {
                    // Queued task finished just in time.
                    if (_Vertices_QueuedLoadLock == null)
                    {
                        return(true);
                    }

                    // If we still can, cancel the queued load, then proceed with lazy-loading.
                    if (MainThreadHelper.IsMainThread)
                    {
                        _Vertices_QueuedLoadLock = null;
                    }
                }

                if (!MainThreadHelper.IsMainThread)
                {
                    // Otherwise wait for it to get loaded, don't reload twice. (Don't wait locked!)
                    while (!_Vertices_QueuedLoad.IsValid)
                    {
                        Thread.Yield();
                    }
                    _Vertices_QueuedLoad.GetResult();
                    return(true);
                }
            }

            if (!(CoreModule.Settings.ThreadedGL ?? Everest.Flags.PreferThreadedGL) && !MainThreadHelper.IsMainThread && queuedLoadLock == null)
            {
                // Let's queue a reload onto the main thread and call it a day.
                lock (queuedLoadLock = new object()) {
                    _Vertices_QueuedLoadLock = queuedLoadLock;
                    _Vertices_QueuedLoad     = MainThreadHelper.Get(() => {
                        lock (queuedLoadLock) {
                            if (_Vertices_QueuedLoadLock == null)
                            {
                                return(Vertices);
                            }
                            // Force-reload as we already returned true on the other thread.
                            Vertices?.Dispose();
                            // NOTE: If something dares to change verts on the fly, make it wait on any existing tasks, then make it force-reload.
                            Vertices = new VertexBuffer(Engine.Graphics.GraphicsDevice, typeof(VertexPositionTexture), verts.Length, BufferUsage.None);
                            Vertices.SetData(verts);
                            _Vertices_QueuedLoadLock = null;
                            return(Vertices);
                        }
                    });
                }
                return(true);
            }

            return(orig_ResetVertexBuffer());
        }
Beispiel #12
0
        public void ctor(Session session, Vector2?startPosition = default(Vector2?))
        {
            if (LastLoadingThread != null &&
                LastLoadingThread.TryGetTarget(out Thread lastThread) &&
                (lastThread?.IsAlive ?? false))
            {
                lastThread?.Abort();
            }

            if (CoreModule.Settings.LazyLoading)
            {
                MainThreadHelper.Do(() => VirtualContentExt.UnloadOverworld());
            }

            // Vanilla TileToIndex mappings.
            SurfaceIndex.TileToIndex = new Dictionary <char, int> {
                { '1', 3 },
                { '3', 4 },
                { '4', 7 },
                { '5', 8 },
                { '6', 8 },
                { '7', 8 },
                { '8', 8 },
                { '9', 13 },
                { 'a', 8 },
                { 'b', 23 },
                { 'c', 8 },
                { 'd', 8 },
                { 'e', 8 },
                { 'f', 8 },
                { 'g', 8 },
                { 'G', 8 }, // Reflection alt - unassigned in vanilla.
                { 'h', 33 },
                { 'i', 4 },
                { 'j', 8 },
                { 'k', 3 },
                { 'l', 25 },
                { 'm', 44 },
                { 'n', 40 },
                { 'o', 43 }
            };

            AreaData area = AreaData.Get(session);
            MapMeta  meta = area.GetMeta();
            string   path;

            path = meta?.BackgroundTiles;
            if (string.IsNullOrEmpty(path))
            {
                path = Path.Combine("Graphics", "BackgroundTiles.xml");
            }
            GFX.BGAutotiler = new Autotiler(path);

            path = meta?.ForegroundTiles;
            if (string.IsNullOrEmpty(path))
            {
                path = Path.Combine("Graphics", "ForegroundTiles.xml");
            }
            GFX.FGAutotiler = new Autotiler(path);

            path = meta?.AnimatedTiles;
            if (string.IsNullOrEmpty(path))
            {
                path = Path.Combine("Graphics", "AnimatedTiles.xml");
            }
            GFX.AnimatedTilesBank = new AnimatedTilesBank();
            XmlElement animatedData = Calc.LoadContentXML(path)["Data"];

            foreach (XmlElement el in animatedData)
            {
                if (el != null)
                {
                    GFX.AnimatedTilesBank.Add(
                        el.Attr("name"),
                        el.AttrFloat("delay", 0f),
                        el.AttrVector2("posX", "posY", Vector2.Zero),
                        el.AttrVector2("origX", "origY", Vector2.Zero),
                        GFX.Game.GetAtlasSubtextures(el.Attr("path"))
                        );
                }
            }

            GFX.SpriteBank = new SpriteBank(GFX.Game, Path.Combine("Graphics", "Sprites.xml"));

            path = meta?.Sprites;
            if (!string.IsNullOrEmpty(path))
            {
                SpriteBank bankOrig = GFX.SpriteBank;
                SpriteBank bankMod  = new SpriteBank(GFX.Game, path);

                foreach (KeyValuePair <string, SpriteData> kvpBank in bankMod.SpriteData)
                {
                    string     key      = kvpBank.Key;
                    SpriteData valueMod = kvpBank.Value;

                    if (bankOrig.SpriteData.TryGetValue(key, out SpriteData valueOrig))
                    {
                        IDictionary animsOrig = valueOrig.Sprite.GetAnimations();
                        IDictionary animsMod  = valueMod.Sprite.GetAnimations();
                        foreach (DictionaryEntry kvpAnim in animsMod)
                        {
                            animsOrig[kvpAnim.Key] = kvpAnim.Value;
                        }

                        valueOrig.Sources.AddRange(valueMod.Sources);

                        // replay the starting animation to be sure it is referring to the new sprite.
                        valueOrig.Sprite.Stop();
                        if (valueMod.Sprite.CurrentAnimationID != "")
                        {
                            valueOrig.Sprite.Play(valueMod.Sprite.CurrentAnimationID);
                        }
                    }
                    else
                    {
                        bankOrig.SpriteData[key] = valueMod;
                    }
                }
            }

            // This is done exactly once in the vanilla GFX.LoadData method.
            PlayerSprite.ClearFramesMetadata();
            PlayerSprite.CreateFramesMetadata("player");
            PlayerSprite.CreateFramesMetadata("player_no_backpack");
            PlayerSprite.CreateFramesMetadata("badeline");
            PlayerSprite.CreateFramesMetadata("player_badeline");
            PlayerSprite.CreateFramesMetadata("player_playback");

            path = meta?.Portraits;
            if (string.IsNullOrEmpty(path))
            {
                path = Path.Combine("Graphics", "Portraits.xml");
            }
            GFX.PortraitsSpriteBank = new SpriteBank(GFX.Portraits, path);

            orig_ctor(session, startPosition);

            LastLoadingThread = patch_RunThread.Current;
        }
Beispiel #13
0
        public new void ResetBillboardBuffers()
        {
            // Checking for IsDisposed on other threads should be fine...
            if (billboardVertices != null && !billboardIndices.IsDisposed && !billboardIndices.GraphicsDevice.IsDisposed &&
                billboardVertices != null && !billboardVertices.IsDisposed && !billboardVertices.GraphicsDevice.IsDisposed &&
                billboardInfo.Length <= billboardVertices.VertexCount)
            {
                return;
            }

            // Handle already queued loads appropriately.
            object queuedLoadLock = _Billboard_QueuedLoadLock;

            if (queuedLoadLock != null)
            {
                lock (queuedLoadLock) {
                    // Queued task finished just in time.
                    if (_Billboard_QueuedLoadLock == null)
                    {
                        return;
                    }

                    // If we still can, cancel the queued load, then proceed with lazy-loading.
                    if (MainThreadHelper.IsMainThread)
                    {
                        _Billboard_QueuedLoadLock = null;
                    }
                }

                if (!MainThreadHelper.IsMainThread)
                {
                    // Otherwise wait for it to get loaded, don't reload twice. (Don't wait locked!)
                    while (!_Billboard_QueuedLoad.IsValid)
                    {
                        Thread.Yield();
                    }
                    _Billboard_QueuedLoad.GetResult();
                    return;
                }
            }

            if (!(CoreModule.Settings.ThreadedGL ?? Everest.Flags.PreferThreadedGL) && !MainThreadHelper.IsMainThread && queuedLoadLock == null)
            {
                // Let's queue a reload onto the main thread and call it a day.
                lock (queuedLoadLock = new object()) {
                    _Billboard_QueuedLoadLock = queuedLoadLock;
                    _Billboard_QueuedLoad     = MainThreadHelper.Get(() => {
                        lock (queuedLoadLock) {
                            if (_Billboard_QueuedLoadLock == null)
                            {
                                return(billboardVertices);
                            }
                            // Force-reload as we already returned true on the other thread.
                            if (billboardVertices != null && !billboardVertices.IsDisposed)
                            {
                                billboardVertices.Dispose();
                            }
                            if (billboardIndices != null && !billboardIndices.IsDisposed)
                            {
                                billboardIndices.Dispose();
                            }
                            // NOTE: If something dares to change verts on the fly, make it wait on any existing tasks, then make it force-reload.
                            // Let's rely on the original code for now.
                            orig_ResetBillboardBuffers();
                            _Billboard_QueuedLoadLock = null;
                            return(billboardVertices);
                        }
                    });
                }
                return;
            }

            orig_ResetBillboardBuffers();
        }
Beispiel #14
0
        public void ctor(Session session, Vector2?startPosition = default(Vector2?))
        {
            if (CoreModule.Settings.LazyLoading)
            {
                MainThreadHelper.Do(() => VirtualContentExt.UnloadOverworld());
            }

            // Vanilla TileToIndex mappings.
            SurfaceIndex.TileToIndex = new Dictionary <char, int> {
                { '1', 3 },
                { '3', 4 },
                { '4', 7 },
                { '5', 8 },
                { '6', 8 },
                { '7', 8 },
                { '8', 8 },
                { '9', 13 },
                { 'a', 8 },
                { 'b', 23 },
                { 'c', 8 },
                { 'd', 8 },
                { 'e', 8 },
                { 'f', 8 },
                { 'g', 8 },
                { 'h', 33 },
                { 'i', 4 },
                { 'j', 8 },
                { 'k', 3 },
                { 'l', 25 },
                { 'm', 44 },
                { 'n', 40 },
                { 'o', 43 }
            };

            AreaData area = AreaData.Get(session);
            MapMeta  meta = area.GetMeta();
            string   path;

            path = meta?.BackgroundTiles;
            if (string.IsNullOrEmpty(path))
            {
                path = Path.Combine("Graphics", "BackgroundTiles.xml");
            }
            GFX.BGAutotiler = new Autotiler(path);

            path = meta?.ForegroundTiles;
            if (string.IsNullOrEmpty(path))
            {
                path = Path.Combine("Graphics", "ForegroundTiles.xml");
            }
            GFX.FGAutotiler = new Autotiler(path);

            path = meta?.AnimatedTiles;
            if (string.IsNullOrEmpty(path))
            {
                path = Path.Combine("Graphics", "AnimatedTiles.xml");
            }
            GFX.AnimatedTilesBank = new AnimatedTilesBank();
            XmlElement animatedData = Calc.LoadContentXML(path)["Data"];

            foreach (XmlElement el in animatedData)
            {
                if (el != null)
                {
                    GFX.AnimatedTilesBank.Add(
                        el.Attr("name"),
                        el.AttrFloat("delay", 0f),
                        el.AttrVector2("posX", "posY", Vector2.Zero),
                        el.AttrVector2("origX", "origY", Vector2.Zero),
                        GFX.Game.GetAtlasSubtextures(el.Attr("path"))
                        );
                }
            }

            GFX.SpriteBank = new SpriteBank(GFX.Game, Path.Combine("Graphics", "Sprites.xml"));

            path = meta?.Sprites;
            if (!string.IsNullOrEmpty(path))
            {
                SpriteBank bankOrig = GFX.SpriteBank;
                SpriteBank bankMod  = new SpriteBank(GFX.Game, path);

                foreach (KeyValuePair <string, SpriteData> kvpBank in bankMod.SpriteData)
                {
                    string     key      = kvpBank.Key;
                    SpriteData valueMod = kvpBank.Value;

                    if (bankOrig.SpriteData.TryGetValue(key, out SpriteData valueOrig))
                    {
                        IDictionary animsOrig = valueOrig.Sprite.GetAnimations();
                        IDictionary animsMod  = valueMod.Sprite.GetAnimations();

                        foreach (DictionaryEntry kvpAnim in animsMod)
                        {
                            animsOrig[kvpAnim.Key] = kvpAnim.Value;
                        }
                    }
                    else
                    {
                        bankOrig.SpriteData[key] = valueMod;
                    }
                }
            }

            path = meta?.Portraits;
            if (string.IsNullOrEmpty(path))
            {
                path = Path.Combine("Graphics", "Portraits.xml");
            }
            GFX.PortraitsSpriteBank = new SpriteBank(GFX.Portraits, path);

            orig_ctor(session, startPosition);
        }
Beispiel #15
0
    public override bool Calculate()
    {
        bool isPMB = false;

        if (!input.connected())
        {
            return(false);
        }
        VoxelBlock <Voxel> block = input.GetValue <VoxelBlock <Voxel> >();

        if (surfaceConnection.connected())
        {
            surface = surfaceConnection.GetValue <float>();
        }

        Marching marching = null;

        switch (mode)
        {
        case VerteGenerationMode.Tetrahedron:
            marching = new MarchingTertrahedron();
            break;

        case VerteGenerationMode.Cubes:
            marching = new MarchingCubes();
            break;

        case VerteGenerationMode.Voxel:
            marching = new VoxelGeneration();
            break;

        case VerteGenerationMode.PMB:
            isPMB = true;
            break;
        }

        //The size of voxel array.
        Vector3Int count  = block.VoxelCount;
        int        width  = count.x;
        int        height = count.y;
        int        length = count.z;

        float[] voxels = new float[width * height * length];

        for (int y = 0; y < height; y++)
        {
            Voxel[,] voxelLayer = block.Layers[y].Layer;
            for (int x = 0; x < width; x++)
            {
                for (int z = 0; z < length; z++)
                {
                    int idx = x + y * width + z * width * height;
                    voxels[idx] = voxelLayer[x, z].GetValue();
                }
            }
        }

        if (isPMB)
        {
            var pmbTask = MainThreadHelper.instance().scheduleOnMainThread(() =>
            {
                pmb.ReInit(block);
                Stopwatch pmbWatch = Stopwatch.StartNew();
                buffers            = pmb.calculate(voxels, width, height, length, surface);
                pmbWatch.Stop();
                UnityEngine.Debug.LogFormat("PMB took {0}ms\n\t{1} voxels\n\t{2} triangles", pmbWatch.ElapsedMilliseconds, voxels.Count(), buffers.indexBuffer.count / 3);
            });

            pmbTask.wait();

            if (!pmbTask.completed)
            {
                return(false);
            }

            Block = block;
            return(true);
        }

        //Surface is the value that represents the surface of mesh
        //For example the perlin noise has a range of -1 to 1 so the mid point is where we want the surface to cut through.
        //The target value does not have to be the mid point it can be any value with in the range.
        //
        //This should be accesible by an input
        marching.Surface = surface;

        List <Vector3> verts   = new List <Vector3>();
        List <int>     indices = new List <int>();
        List <Vector3> normals = new List <Vector3>();

        Stopwatch sw = Stopwatch.StartNew();

        marching.Generate(voxels, width, height, length, verts, indices, normals);

        sw.Stop();

        UnityEngine.Debug.LogFormat("Marching took {0}ms\n\t{1} vertices; {2} triangles", sw.ElapsedMilliseconds, verts.Count(), indices.Count() / 3);

        sw.Restart();
        weldVertices(verts, indices, normals);
        sw.Stop();

        UnityEngine.Debug.LogFormat("Vertex welding took {0}ms\n\t {1} vertices left", sw.ElapsedMilliseconds, verts.Count());

        var task = MainThreadHelper.instance().scheduleOnMainThread(() =>
        {
            buffers = new RenderBuffers {
                vertexBuffer = new ComputeBuffer(verts.Count, sizeof(float) * 3),
                indexBuffer  = new ComputeBuffer(indices.Count, sizeof(int)),
                normalBuffer = new ComputeBuffer(normals.Count, sizeof(float) * 3),
                argsBuffer   = new ComputeBuffer(4, sizeof(int), ComputeBufferType.IndirectArguments),
            };

            buffers.vertexBuffer.SetData(verts);
            buffers.indexBuffer.SetData(indices);
            buffers.normalBuffer.SetData(normals);
            buffers.argsBuffer.SetData(new int[] { indices.Count, 1, 0, 0 });
        });

        task.wait();

        if (!task.completed)
        {
            return(false);
        }

        Block = block;

        return(true);
    }