Ejemplo n.º 1
0
        partial void DisposeTexture()
        {
            //check if another sprite is using the same texture
            if (!string.IsNullOrEmpty(FilePath)) //file can be empty if the sprite is created directly from a Texture2D instance
            {
                lock (list)
                {
                    foreach (Sprite s in LoadedSprites)
                    {
                        if (s.FullPath == FullPath)
                        {
                            return;
                        }
                    }
                }
            }

            //if not, free the texture
            if (texture != null)
            {
                CrossThread.RequestExecutionOnMainThread(() =>
                {
                    texture.Dispose();
                });
                texture = null;
            }
        }
Ejemplo n.º 2
0
        public static Texture2D LoadTexture(string file, bool preMultiplyAlpha = true)
        {
            if (string.IsNullOrWhiteSpace(file))
            {
                Texture2D t = null;
                CrossThread.RequestExecutionOnMainThread(() =>
                {
                    t = new Texture2D(GameMain.GraphicsDeviceManager.GraphicsDevice, 1, 1);
                });
                return(t);
            }
            file = Path.GetFullPath(file);
            foreach (Sprite s in list)
            {
                if (s.FullPath == file && s.texture != null)
                {
                    return(s.texture);
                }
            }

            if (File.Exists(file))
            {
                ToolBox.IsProperFilenameCase(file);
                return(TextureLoader.FromFile(file, preMultiplyAlpha));
            }
            else
            {
                DebugConsole.ThrowError("Sprite \"" + file + "\" not found!");
            }

            return(null);
        }
Ejemplo n.º 3
0
        public static Texture2D FromStream(Stream fileStream, bool preMultiplyAlpha = true, string path = null)
        {
            try
            {
                int    width = 0; int height = 0; int channels = 0;
                byte[] textureData = null;
                textureData = Texture2D.TextureDataFromStream(fileStream, out width, out height, out channels);
                if (preMultiplyAlpha)
                {
                    PreMultiplyAlpha(ref textureData);
                }
                Texture2D tex = null;
                CrossThread.RequestExecutionOnMainThread(() =>
                {
                    tex = new Texture2D(_graphicsDevice, width, height);
                    tex.SetData(textureData);
                });
                return(tex);
            }
            catch (Exception e)
            {
#if WINDOWS
                if (e is SharpDX.SharpDXException)
                {
                    throw;
                }
#endif

                DebugConsole.ThrowError("Loading texture from stream failed!", e);
                return(null);
            }
        }
Ejemplo n.º 4
0
        public static Texture2D FromStream(Stream fileStream, string path = null, bool mipmap = false)
        {
            try
            {
                int    width = 0; int height = 0; int channels = 0;
                byte[] textureData = null;
                textureData = Texture2D.TextureDataFromStream(fileStream, out width, out height, out channels);

                Texture2D tex = null;
                CrossThread.RequestExecutionOnMainThread(() =>
                {
                    tex = new Texture2D(_graphicsDevice, width, height, mipmap, SurfaceFormat.Color);
                    tex.SetData(textureData);
                });
                return(tex);
            }
            catch (Exception e)
            {
#if WINDOWS
                if (e is SharpDX.SharpDXException)
                {
                    throw;
                }
#endif

                DebugConsole.ThrowError("Loading texture from stream failed!", e);
                return(null);
            }
        }
Ejemplo n.º 5
0
 public static Texture2D FromStream(Stream fileStream, bool preMultiplyAlpha = true, string path = null)
 {
     try
     {
         int    width = 0; int height = 0; int channels = 0;
         byte[] textureData = null;
         Task   loadTask    = Task.Run(() =>
         {
             textureData = Texture2D.TextureDataFromStream(fileStream, out width, out height, out channels);
         });
         bool success = loadTask.Wait(10000);
         if (!success)
         {
             DebugConsole.ThrowError("Failed to load texture data from " + (path ?? "stream") + ": timed out");
             return(null);
         }
         if (preMultiplyAlpha)
         {
             PreMultiplyAlpha(ref textureData);
         }
         Texture2D tex = null;
         CrossThread.RequestExecutionOnMainThread(() =>
         {
             tex = new Texture2D(_graphicsDevice, width, height);
             tex.SetData(textureData);
         });
         return(tex);
     }
     catch (Exception e)
     {
         DebugConsole.ThrowError("Loading texture from stream failed!", e);
         return(null);
     }
 }
Ejemplo n.º 6
0
        public static Texture2D FromStream(System.IO.Stream stream, string path = null, bool compress = true, bool mipmap = false)
        {
            try
            {
                path = path.CleanUpPath();
                byte[] textureData = null;
                textureData = Texture2D.TextureDataFromStream(stream, out int width, out int height, out int channels);

                SurfaceFormat format = SurfaceFormat.Color;
                if (GameMain.Config.TextureCompressionEnabled && compress)
                {
                    if (((width & 0x03) == 0) && ((height & 0x03) == 0))
                    {
                        textureData = CompressDxt5(textureData, width, height);
                        format      = SurfaceFormat.Dxt5;
                        mipmap      = false;
                    }
                    else
                    {
                        DebugConsole.NewMessage($"Could not compress a texture because the dimensions aren't a multiple of 4 (path: {path ?? "null"}, size: {width}x{height})", Color.Orange);
                    }
                }

                if (((width & 0x03) != 0) || ((height & 0x03) != 0))
                {
                    DebugConsole.AddWarning($"Cannot compress a texture because the dimensions are not a multiple of 4 (path: {path ?? "null"}, size: {width}x{height})");
                }

                Texture2D tex = null;
                CrossThread.RequestExecutionOnMainThread(() =>
                {
                    if (cancelAll)
                    {
                        return;
                    }
                    tex = new Texture2D(_graphicsDevice, width, height, mipmap, format);
                    tex.SetData(textureData);
                });
                return(tex);
            }
            catch (Exception e)
            {
#if WINDOWS
                if (e is SharpDX.SharpDXException)
                {
                    throw;
                }
#endif

                DebugConsole.ThrowError(string.IsNullOrEmpty(path) ? "Loading texture from stream failed!" :
                                        "Loading texture \"" + path + "\" failed!", e);
                return(null);
            }
        }
Ejemplo n.º 7
0
        private static Texture2D GetTexture(SpriteBatch spriteBatch)
        {
            if (_whitePixelTexture == null)
            {
                CrossThread.RequestExecutionOnMainThread(() =>
                {
                    _whitePixelTexture = new Texture2D(spriteBatch.GraphicsDevice, 1, 1, false, SurfaceFormat.Color);
                    _whitePixelTexture.SetData(new[] { Color.White });
                });
            }

            return(_whitePixelTexture);
        }
Ejemplo n.º 8
0
        public static void Init(GraphicsDevice graphicsDevice, bool needsBmp = false)
        {
            _graphicsDevice = graphicsDevice;

            Color[] data = new Color[32 * 32];
            for (int i = 0; i < 32 * 32; i++)
            {
                data[i] = Color.Magenta;
            }

            CrossThread.RequestExecutionOnMainThread(() =>
            {
                PlaceHolderTexture = new Texture2D(graphicsDevice, 32, 32);
                PlaceHolderTexture.SetData(data);
            });
        }
Ejemplo n.º 9
0
        public static Texture2D LoadTexture(string file, out Sprite reusedSprite, bool compress = true)
        {
            reusedSprite = null;
            if (string.IsNullOrWhiteSpace(file))
            {
                Texture2D t = null;
                CrossThread.RequestExecutionOnMainThread(() =>
                {
                    t = new Texture2D(GameMain.GraphicsDeviceManager.GraphicsDevice, 1, 1);
                });
                return(t);
            }
            string fullPath = Path.GetFullPath(file);

            foreach (Sprite s in LoadedSprites)
            {
                if (s.FullPath == fullPath && s.texture != null && !s.texture.IsDisposed)
                {
                    reusedSprite = s;
                    return(s.texture);
                }
            }

            if (File.Exists(file))
            {
                if (!ToolBox.IsProperFilenameCase(file))
                {
#if DEBUG
                    DebugConsole.ThrowError("Texture file \"" + file + "\" has incorrect case!");
#endif
                }
                return(TextureLoader.FromFile(file, compress));
            }
            else
            {
                DebugConsole.ThrowError($"Sprite \"{file}\" not found! {Environment.StackTrace.CleanupStackTrace()}");
            }

            return(null);
        }
Ejemplo n.º 10
0
        partial void GenerateNoiseMapProjSpecific()
        {
            if (noiseTexture == null)
            {
                CrossThread.RequestExecutionOnMainThread(() =>
                {
                    noiseTexture    = new Texture2D(GameMain.Instance.GraphicsDevice, generationParams.NoiseResolution, generationParams.NoiseResolution);
                    rawNoiseTexture = new Texture2D(GameMain.Instance.GraphicsDevice, generationParams.NoiseResolution, generationParams.NoiseResolution);
                });
                rawNoiseSprite = new Sprite(rawNoiseTexture, null, null);
            }

            Color[] crackTextureData    = new Color[generationParams.NoiseResolution * generationParams.NoiseResolution];
            Color[] noiseTextureData    = new Color[generationParams.NoiseResolution * generationParams.NoiseResolution];
            Color[] rawNoiseTextureData = new Color[generationParams.NoiseResolution * generationParams.NoiseResolution];
            for (int x = 0; x < generationParams.NoiseResolution; x++)
            {
                for (int y = 0; y < generationParams.NoiseResolution; y++)
                {
                    noiseTextureData[x + y * generationParams.NoiseResolution]    = Color.Lerp(Color.Black, Color.Transparent, Noise[x, y]);
                    rawNoiseTextureData[x + y * generationParams.NoiseResolution] = Color.Lerp(Color.Black, Color.White, Rand.Range(0.0f, 1.0f));
                }
            }

            float   mapRadius = size / 2;
            Vector2 mapCenter = Vector2.One * mapRadius;

            foreach (LocationConnection connection in connections)
            {
                float centerDist = Vector2.Distance(connection.CenterPos, mapCenter);

                Vector2 connectionStart  = connection.Locations[0].MapPosition;
                Vector2 connectionEnd    = connection.Locations[1].MapPosition;
                float   connectionLength = Vector2.Distance(connectionStart, connectionEnd);
                int     iterations       = (int)(Math.Sqrt(connectionLength * generationParams.ConnectionIndicatorIterationMultiplier));
                connection.CrackSegments = MathUtils.GenerateJaggedLine(
                    connectionStart, connectionEnd,
                    iterations, connectionLength * generationParams.ConnectionIndicatorDisplacementMultiplier);

                iterations = (int)(Math.Sqrt(connectionLength * generationParams.ConnectionIterationMultiplier));
                var visualCrackSegments = MathUtils.GenerateJaggedLine(
                    connectionStart, connectionEnd,
                    iterations, connectionLength * generationParams.ConnectionDisplacementMultiplier);

                float totalLength = Vector2.Distance(visualCrackSegments[0][0], visualCrackSegments.Last()[1]);
                for (int i = 0; i < visualCrackSegments.Count; i++)
                {
                    Vector2 start = visualCrackSegments[i][0] * (generationParams.NoiseResolution / (float)size);
                    Vector2 end   = visualCrackSegments[i][1] * (generationParams.NoiseResolution / (float)size);

                    float length = Vector2.Distance(start, end);
                    for (float x = 0; x < 1; x += 1.0f / length)
                    {
                        Vector2 pos = Vector2.Lerp(start, end, x);
                        SetNoiseColorOnArea(pos, MathHelper.Clamp((int)(totalLength / 30), 2, 5) + Rand.Range(-1, 1), Color.Transparent);
                    }
                }
            }

            void SetNoiseColorOnArea(Vector2 pos, int dist, Color color)
            {
                for (int x = -dist; x < dist; x++)
                {
                    for (int y = -dist; y < dist; y++)
                    {
                        float d = 1.0f - new Vector2(x, y).Length() / dist;
                        if (d <= 0)
                        {
                            continue;
                        }

                        int xIndex = (int)pos.X + x;
                        if (xIndex < 0 || xIndex >= generationParams.NoiseResolution)
                        {
                            continue;
                        }
                        int yIndex = (int)pos.Y + y;
                        if (yIndex < 0 || yIndex >= generationParams.NoiseResolution)
                        {
                            continue;
                        }

                        float perlin = (float)PerlinNoise.CalculatePerlin(
                            xIndex / (float)generationParams.NoiseResolution * 100.0f,
                            yIndex / (float)generationParams.NoiseResolution * 100.0f, 0);

                        byte a = Math.Max(crackTextureData[xIndex + yIndex * generationParams.NoiseResolution].A, (byte)((d * perlin) * 255));

                        crackTextureData[xIndex + yIndex * generationParams.NoiseResolution].A = a;
                    }
                }
            }

            for (int i = 0; i < noiseTextureData.Length; i++)
            {
                float darken    = noiseTextureData[i].A / 255.0f;
                Color pathColor = Color.Lerp(Color.White, Color.Transparent, noiseTextureData[i].A / 255.0f);
                noiseTextureData[i] =
                    Color.Lerp(noiseTextureData[i], pathColor, crackTextureData[i].A / 255.0f * 0.5f);
            }

            CrossThread.RequestExecutionOnMainThread(() =>
            {
                noiseTexture.SetData(noiseTextureData);
                rawNoiseTexture.SetData(rawNoiseTextureData);
            });
        }
Ejemplo n.º 11
0
        public void End()
        {
            if (isDisposed)
            {
                return;
            }
            //sort commands according to the sorting
            //mode given in the last Begin call
            switch (currentSortMode)
            {
            case SpriteSortMode.FrontToBack:
                commandList.Sort((c1, c2) =>
                {
                    return(c1.Depth <c2.Depth ? -1
                                     : c1.Depth> c2.Depth ? 1
                             : c1.Index <c2.Index ? 1
                                         : c1.Index> c2.Index ? -1
                             : 0);
                });
                break;

            case SpriteSortMode.BackToFront:
                commandList.Sort((c1, c2) =>
                {
                    return(c1.Depth <c2.Depth ? 1
                                     : c1.Depth> c2.Depth ? -1
                             : c1.Index <c2.Index ? 1
                                         : c1.Index> c2.Index ? -1
                             : 0);
                });
                break;
            }

            //try to place commands of the same texture
            //contiguously for optimal buffer generation
            //while maintaining the same visual result
            for (int i = 1; i < commandList.Count; i++)
            {
                if (commandList[i].Texture != commandList[i - 1].Texture)
                {
                    for (int j = i - 1; j >= 0; j--)
                    {
                        if (commandList[j].Texture == commandList[i].Texture)
                        {
                            //no commands between i and j overlap with
                            //i, therefore we can safely sift i down to
                            //make a contiguous block
                            commandList.SiftElement(i, j + 1);
                            break;
                        }
                        else if (commandList[j].Overlaps(commandList[i]))
                        {
                            //an overlapping command was found, therefore
                            //attempting to sift this one down would change
                            //the visual result
                            break;
                        }
                    }
                }
            }

            if (isDisposed)
            {
                return;
            }
            //each contiguous block of commands of the same texture
            //requires a vertex buffer to be rendered
            CrossThread.RequestExecutionOnMainThread(() =>
            {
                if (commandList.Count == 0)
                {
                    return;
                }
                int startIndex = 0;
                for (int i = 1; i < commandList.Count; i++)
                {
                    if (commandList[i].Texture != commandList[startIndex].Texture)
                    {
                        maxSpriteCount = Math.Max(maxSpriteCount, i - startIndex);
                        recordedBuffers.Add(new RecordedBuffer(commandList, startIndex, i - startIndex));
                        startIndex = i;
                    }
                }
                recordedBuffers.Add(new RecordedBuffer(commandList, startIndex, commandList.Count - startIndex));
                maxSpriteCount = Math.Max(maxSpriteCount, commandList.Count - startIndex);
            });

            commandList.Clear();

            ReadyToRender = true;
        }
Ejemplo n.º 12
0
        private IEnumerable <object> Load(bool isSeparateThread)
        {
            if (GameSettings.VerboseLogging)
            {
                DebugConsole.NewMessage("LOADING COROUTINE", Color.Lime);
            }

            while (TitleScreen.WaitForLanguageSelection)
            {
                yield return(CoroutineStatus.Running);
            }

            SoundManager = new Sounds.SoundManager();
            SoundManager.SetCategoryGainMultiplier("default", Config.SoundVolume, 0);
            SoundManager.SetCategoryGainMultiplier("ui", Config.SoundVolume, 0);
            SoundManager.SetCategoryGainMultiplier("waterambience", Config.SoundVolume, 0);
            SoundManager.SetCategoryGainMultiplier("music", Config.MusicVolume, 0);
            SoundManager.SetCategoryGainMultiplier("voip", Math.Min(Config.VoiceChatVolume, 1.0f), 0);

            if (Config.EnableSplashScreen && !ConsoleArguments.Contains("-skipintro"))
            {
                var   pendingSplashScreens = TitleScreen.PendingSplashScreens;
                float baseVolume           = MathHelper.Clamp(Config.SoundVolume * 2.0f, 0.0f, 1.0f);
                pendingSplashScreens?.Enqueue(new LoadingScreen.PendingSplashScreen("Content/SplashScreens/Splash_UTG.webm", baseVolume * 0.5f));
                pendingSplashScreens?.Enqueue(new LoadingScreen.PendingSplashScreen("Content/SplashScreens/Splash_FF.webm", baseVolume));
                pendingSplashScreens?.Enqueue(new LoadingScreen.PendingSplashScreen("Content/SplashScreens/Splash_Daedalic.webm", baseVolume * 0.1f));
            }

            //if not loading in a separate thread, wait for the splash screens to finish before continuing the loading
            //otherwise the videos will look extremely choppy
            if (!isSeparateThread)
            {
                while (TitleScreen.PlayingSplashScreen || TitleScreen.PendingSplashScreens.Count > 0)
                {
                    yield return(CoroutineStatus.Running);
                }
            }

            GUI.Init(Window, Config.SelectedContentPackages, GraphicsDevice);
            DebugConsole.Init();

            if (Config.AutoUpdateWorkshopItems)
            {
                bool waitingForWorkshopUpdates = true;
                bool result = false;
                TaskPool.Add(SteamManager.AutoUpdateWorkshopItemsAsync(), (task) =>
                {
                    result = task.Result;
                    waitingForWorkshopUpdates = false;
                });

                while (waitingForWorkshopUpdates)
                {
                    yield return(CoroutineStatus.Running);
                }

                if (result)
                {
                    CrossThread.RequestExecutionOnMainThread(() =>
                    {
                        ContentPackage.LoadAll();
                        Config.ReloadContentPackages();
                    });
                }
            }


            if (SelectedPackages.None())
            {
                DebugConsole.Log("No content packages selected");
            }
            else
            {
                DebugConsole.Log("Selected content packages: " + string.Join(", ", SelectedPackages.Select(cp => cp.Name)));
            }

#if DEBUG
            GameSettings.ShowUserStatisticsPrompt = false;
            GameSettings.SendUserStatistics       = false;
#endif

            InitUserStats();

            yield return(CoroutineStatus.Running);

            Debug.WriteLine("sounds");

            int i = 0;
            foreach (object crObj in SoundPlayer.Init())
            {
                CoroutineStatus status = (CoroutineStatus)crObj;
                if (status == CoroutineStatus.Success)
                {
                    break;
                }

                i++;
                TitleScreen.LoadState = SoundPlayer.SoundCount == 0 ?
                                        1.0f :
                                        Math.Min(40.0f * i / Math.Max(SoundPlayer.SoundCount, 1), 40.0f);

                yield return(CoroutineStatus.Running);
            }

            TitleScreen.LoadState = 40.0f;
            yield return(CoroutineStatus.Running);

            LightManager = new Lights.LightManager(base.GraphicsDevice, Content);

            TitleScreen.LoadState = 41.0f;
            yield return(CoroutineStatus.Running);

            GUI.LoadContent();
            TitleScreen.LoadState = 42.0f;

            yield return(CoroutineStatus.Running);

            CharacterPrefab.LoadAll();
            MissionPrefab.Init();
            TraitorMissionPrefab.Init();
            MapEntityPrefab.Init();
            Tutorials.Tutorial.Init();
            MapGenerationParams.Init();
            LevelGenerationParams.LoadPresets();
            WreckAIConfig.LoadAll();
            ScriptedEventSet.LoadPrefabs();
            AfflictionPrefab.LoadAll(GetFilesOfType(ContentType.Afflictions));
            SkillSettings.Load(GetFilesOfType(ContentType.SkillSettings));
            Order.Init();
            EventManagerSettings.Init();
            TitleScreen.LoadState = 50.0f;
            yield return(CoroutineStatus.Running);

            StructurePrefab.LoadAll(GetFilesOfType(ContentType.Structure));
            TitleScreen.LoadState = 53.0f;
            yield return(CoroutineStatus.Running);

            ItemPrefab.LoadAll(GetFilesOfType(ContentType.Item));
            TitleScreen.LoadState = 55.0f;
            yield return(CoroutineStatus.Running);

            JobPrefab.LoadAll(GetFilesOfType(ContentType.Jobs));
            CorpsePrefab.LoadAll(GetFilesOfType(ContentType.Corpses));

            NPCConversation.LoadAll(GetFilesOfType(ContentType.NPCConversations));

            ItemAssemblyPrefab.LoadAll();
            TitleScreen.LoadState = 60.0f;
            yield return(CoroutineStatus.Running);

            GameModePreset.Init();

            SubmarineInfo.RefreshSavedSubs();

            TitleScreen.LoadState = 65.0f;
            yield return(CoroutineStatus.Running);

            GameScreen = new GameScreen(GraphicsDeviceManager.GraphicsDevice, Content);

            TitleScreen.LoadState = 68.0f;
            yield return(CoroutineStatus.Running);

            MainMenuScreen   = new MainMenuScreen(this);
            LobbyScreen      = new LobbyScreen();
            ServerListScreen = new ServerListScreen();

            TitleScreen.LoadState = 70.0f;
            yield return(CoroutineStatus.Running);

#if USE_STEAM
            SteamWorkshopScreen = new SteamWorkshopScreen();
            if (SteamManager.IsInitialized)
            {
                Steamworks.SteamFriends.OnGameRichPresenceJoinRequested += OnInvitedToGame;
                Steamworks.SteamFriends.OnGameLobbyJoinRequested        += OnLobbyJoinRequested;
            }
#endif

            SubEditorScreen = new SubEditorScreen();

            TitleScreen.LoadState = 75.0f;
            yield return(CoroutineStatus.Running);

            ParticleEditorScreen = new ParticleEditorScreen();

            TitleScreen.LoadState = 80.0f;
            yield return(CoroutineStatus.Running);

            LevelEditorScreen     = new LevelEditorScreen();
            SpriteEditorScreen    = new SpriteEditorScreen();
            CharacterEditorScreen = new CharacterEditor.CharacterEditorScreen();

            yield return(CoroutineStatus.Running);

            TitleScreen.LoadState = 85.0f;
            ParticleManager       = new ParticleManager(GameScreen.Cam);
            ParticleManager.LoadPrefabs();
            TitleScreen.LoadState = 88.0f;
            LevelObjectPrefab.LoadAll();

            TitleScreen.LoadState = 90.0f;
            yield return(CoroutineStatus.Running);

            DecalManager = new DecalManager();
            LocationType.Init();
            MainMenuScreen.Select();

            CheckContentPackage();

            foreach (string steamError in SteamManager.InitializationErrors)
            {
                new GUIMessageBox(TextManager.Get("Error"), TextManager.Get(steamError));
            }

            TitleScreen.LoadState = 100.0f;
            hasLoaded             = true;
            if (GameSettings.VerboseLogging)
            {
                DebugConsole.NewMessage("LOADING COROUTINE FINISHED", Color.Lime);
            }
            yield return(CoroutineStatus.Success);
        }
Ejemplo n.º 13
0
        public void DynamicRenderAtlas(GraphicsDevice gd, uint character, int texDims = 1024, uint baseChar = 0x54)
        {
            if (System.Threading.Thread.CurrentThread != GameMain.MainThread)
            {
                CrossThread.RequestExecutionOnMainThread(() =>
                {
                    DynamicRenderAtlas(gd, character, texDims, baseChar);
                });
                return;
            }

            byte[]      bitmap;
            int         glyphWidth; int glyphHeight;
            Fixed26Dot6 horizontalAdvance;
            Vector2     drawOffset;

            lock (mutex)
            {
                if (texCoords.ContainsKey(character))
                {
                    return;
                }
                if (textures.Count == 0)
                {
                    this.texDims  = texDims;
                    this.baseChar = baseChar;
                    face.SetPixelSizes(0, size);
                    face.LoadGlyph(face.GetCharIndex(baseChar), LoadFlags.Default, LoadTarget.Normal);
                    baseHeight = face.Glyph.Metrics.Height.ToInt32();
                    textures.Add(new Texture2D(gd, texDims, texDims, false, SurfaceFormat.Color));
                }

                uint glyphIndex = face.GetCharIndex(character);
                if (glyphIndex == 0)
                {
                    return;
                }

                face.SetPixelSizes(0, size);
                face.LoadGlyph(glyphIndex, LoadFlags.Default, LoadTarget.Normal);
                if (face.Glyph.Metrics.Width == 0 || face.Glyph.Metrics.Height == 0)
                {
                    if (face.Glyph.Metrics.HorizontalAdvance > 0)
                    {
                        //glyph is empty, but char still applies advance
                        GlyphData blankData = new GlyphData();
                        blankData.advance  = (float)face.Glyph.Metrics.HorizontalAdvance;
                        blankData.texIndex = -1; //indicates no texture because the glyph is empty
                        texCoords.Add(character, blankData);
                    }
                    return;
                }

                //stacktrace doesn't really work that well when RenderGlyph throws an exception
                face.Glyph.RenderGlyph(RenderMode.Normal);
                bitmap            = (byte[])face.Glyph.Bitmap.BufferData.Clone();
                glyphWidth        = face.Glyph.Bitmap.Width;
                glyphHeight       = bitmap.Length / glyphWidth;
                horizontalAdvance = face.Glyph.Metrics.HorizontalAdvance;
                drawOffset        = new Vector2(face.Glyph.BitmapLeft, baseHeight * 14 / 10 - face.Glyph.BitmapTop);

                if (glyphWidth > texDims - 1 || glyphHeight > texDims - 1)
                {
                    throw new Exception(filename + ", " + size.ToString() + ", " + (char)character + "; Glyph dimensions exceed texture atlas dimensions");
                }

                currentDynamicAtlasNextY = Math.Max(currentDynamicAtlasNextY, glyphHeight + 2);
                if (currentDynamicAtlasCoords.X + glyphWidth + 2 > texDims - 1)
                {
                    currentDynamicAtlasCoords.X  = 0;
                    currentDynamicAtlasCoords.Y += currentDynamicAtlasNextY;
                    currentDynamicAtlasNextY     = 0;
                }
                //no more room in current texture atlas, create a new one
                if (currentDynamicAtlasCoords.Y + glyphHeight + 2 > texDims - 1)
                {
                    currentDynamicAtlasCoords.X = 0;
                    currentDynamicAtlasCoords.Y = 0;
                    currentDynamicAtlasNextY    = 0;
                    textures.Add(new Texture2D(gd, texDims, texDims, false, SurfaceFormat.Color));
                    currentDynamicPixelBuffer = null;
                }

                GlyphData newData = new GlyphData
                {
                    advance    = (float)horizontalAdvance,
                    texIndex   = textures.Count - 1,
                    texCoords  = new Rectangle((int)currentDynamicAtlasCoords.X, (int)currentDynamicAtlasCoords.Y, glyphWidth, glyphHeight),
                    drawOffset = drawOffset
                };
                texCoords.Add(character, newData);

                if (currentDynamicPixelBuffer == null)
                {
                    currentDynamicPixelBuffer = new uint[texDims * texDims];
                    textures[newData.texIndex].GetData <uint>(currentDynamicPixelBuffer, 0, texDims * texDims);
                }

                for (int y = 0; y < glyphHeight; y++)
                {
                    for (int x = 0; x < glyphWidth; x++)
                    {
                        byte byteColor = bitmap[x + y * glyphWidth];
                        currentDynamicPixelBuffer[((int)currentDynamicAtlasCoords.X + x) + ((int)currentDynamicAtlasCoords.Y + y) * texDims] = (uint)(byteColor << 24 | 0x00ffffff);
                    }
                }
                textures[newData.texIndex].SetData <uint>(currentDynamicPixelBuffer);

                currentDynamicAtlasCoords.X += glyphWidth + 2;
            }
        }
Ejemplo n.º 14
0
        /// <summary>
        /// Renders the font into at least one texture atlas, which is simply a collection of all glyphs in the ranges defined by charRanges.
        /// Don't call this too often or with very large sizes.
        /// </summary>
        /// <param name="gd">Graphics device, required to create textures.</param>
        /// <param name="charRanges">Character ranges between each even element with their corresponding odd element. Default is 0x20 to 0xFFFF.</param>
        /// <param name="texDims">Texture dimensions. Default is 512x512.</param>
        /// <param name="baseChar">Base character used to shift all other characters downwards when rendering. Defaults to T.</param>
        public void RenderAtlas(GraphicsDevice gd, uint[] charRanges = null, int texDims = 1024, uint baseChar = 0x54)
        {
            if (DynamicLoading)
            {
                return;
            }

            if (charRanges == null)
            {
                charRanges = new uint[] { 0x20, 0xFFFF };
            }
            this.charRanges = charRanges;
            this.texDims    = texDims;
            this.baseChar   = baseChar;

            textures.ForEach(t => t.Dispose());
            textures.Clear();
            texCoords.Clear();

            uint[] pixelBuffer = new uint[texDims * texDims];
            for (int i = 0; i < texDims * texDims; i++)
            {
                pixelBuffer[i] = 0;
            }

            CrossThread.RequestExecutionOnMainThread(() =>
            {
                textures.Add(new Texture2D(gd, texDims, texDims, false, SurfaceFormat.Color));
            });
            int texIndex = 0;

            Vector2 currentCoords = Vector2.Zero;
            int     nextY         = 0;

            lock (mutex)
            {
                face.SetPixelSizes(0, size);
                face.LoadGlyph(face.GetCharIndex(baseChar), LoadFlags.Default, LoadTarget.Normal);
                baseHeight = face.Glyph.Metrics.Height.ToInt32();

                for (int i = 0; i < charRanges.Length; i += 2)
                {
                    uint start = charRanges[i];
                    uint end   = charRanges[i + 1];
                    for (uint j = start; j <= end; j++)
                    {
                        uint glyphIndex = face.GetCharIndex(j);
                        if (glyphIndex == 0)
                        {
                            continue;
                        }
                        face.LoadGlyph(glyphIndex, LoadFlags.Default, LoadTarget.Normal);
                        if (face.Glyph.Metrics.Width == 0 || face.Glyph.Metrics.Height == 0)
                        {
                            if (face.Glyph.Metrics.HorizontalAdvance > 0)
                            {
                                //glyph is empty, but char still applies advance
                                GlyphData blankData = new GlyphData();
                                blankData.advance  = (float)face.Glyph.Metrics.HorizontalAdvance;
                                blankData.texIndex = -1; //indicates no texture because the glyph is empty
                                texCoords.Add(j, blankData);
                            }
                            continue;
                        }
                        //stacktrace doesn't really work that well when RenderGlyph throws an exception
                        face.Glyph.RenderGlyph(RenderMode.Normal);
                        byte[] bitmap      = face.Glyph.Bitmap.BufferData;
                        int    glyphWidth  = face.Glyph.Bitmap.Width;
                        int    glyphHeight = bitmap.Length / glyphWidth;

                        //if (glyphHeight>lineHeight) lineHeight=glyphHeight;

                        if (glyphWidth > texDims - 1 || glyphHeight > texDims - 1)
                        {
                            throw new Exception(filename + ", " + size.ToString() + ", " + (char)j + "; Glyph dimensions exceed texture atlas dimensions");
                        }

                        nextY = Math.Max(nextY, glyphHeight + 2);

                        if (currentCoords.X + glyphWidth + 2 > texDims - 1)
                        {
                            currentCoords.X  = 0;
                            currentCoords.Y += nextY;
                            nextY            = 0;
                        }
                        if (currentCoords.Y + glyphHeight + 2 > texDims - 1)
                        {
                            currentCoords.X = 0;
                            currentCoords.Y = 0;
                            CrossThread.RequestExecutionOnMainThread(() =>
                            {
                                textures[texIndex].SetData <uint>(pixelBuffer);
                                textures.Add(new Texture2D(gd, texDims, texDims, false, SurfaceFormat.Color));
                            });
                            texIndex++;
                            for (int k = 0; k < texDims * texDims; k++)
                            {
                                pixelBuffer[k] = 0;
                            }
                        }

                        GlyphData newData = new GlyphData
                        {
                            advance    = (float)face.Glyph.Metrics.HorizontalAdvance,
                            texIndex   = texIndex,
                            texCoords  = new Rectangle((int)currentCoords.X, (int)currentCoords.Y, glyphWidth, glyphHeight),
                            drawOffset = new Vector2(face.Glyph.BitmapLeft, baseHeight * 14 / 10 - face.Glyph.BitmapTop)
                        };
                        texCoords.Add(j, newData);

                        for (int y = 0; y < glyphHeight; y++)
                        {
                            for (int x = 0; x < glyphWidth; x++)
                            {
                                byte byteColor = bitmap[x + y * glyphWidth];
                                pixelBuffer[((int)currentCoords.X + x) + ((int)currentCoords.Y + y) * texDims] = (uint)(byteColor << 24 | 0x00ffffff);
                            }
                        }

                        currentCoords.X += glyphWidth + 2;
                    }
                    CrossThread.RequestExecutionOnMainThread(() =>
                    {
                        textures[texIndex].SetData <uint>(pixelBuffer);
                    });
                }
            }
        }