Beispiel #1
0
 internal CharacterInfo(TTF ttf, int index, Vector2 advance)
 {
     this.ttf     = ttf;
     this.index   = index;
     this.texture = null;
     this.advance = advance;
 }
Beispiel #2
0
 internal CharacterInfo(TTF ttf, int index, Vector2 advance, Texture texture, Vector2 bitmapOffset)
 {
     this.ttf          = ttf;
     this.index        = index;
     this.texture      = texture;
     this.bitmapOffset = bitmapOffset;
     this.advance      = advance;
 }
Beispiel #3
0
 public void Unload()
 {
     if (Loaded)
     {
         TTF.CloseFont(Handle);
         Handle = IntPtr.Zero;
         Loaded = false;
     }
 }
 public unsafe ToolInfoWrapper(T handle, TTF flags = default, string?text = null)
 {
     Info = new TTOOLINFOW
     {
         hwnd   = handle.Handle,
         uId    = handle.Handle,
         uFlags = flags | TTF.IDISHWND
     };
     Text    = text;
     _handle = handle;
 }
 public unsafe ToolInfoWrapper(T handle, IntPtr id, TTF flags = default, string?text = null, RECT rect = default)
 {
     Info = new TTOOLINFOW
     {
         hwnd   = handle.Handle,
         uId    = id,
         uFlags = flags,
         rect   = rect
     };
     Text    = text;
     _handle = handle;
 }
            public unsafe ToolInfoWrapper(object handle, TTF flags = default, string text = null)
            {
                IntPtr hwnd = GetHWND(handle);

                Info = new TTOOLINFOW
                {
                    hwnd   = hwnd,
                    uId    = hwnd,
                    uFlags = flags | TTF.IDISHWND
                };
                Text    = text;
                _handle = handle;
            }
Beispiel #7
0
        public void Load()
        {
            if (!Loaded)
            {
                Handle = TTF.OpenFontRW(Resources.CreateRWFromFile(Filename, FileAssembly), 1, PointSize);

                if (Handle != IntPtr.Zero)
                {
                    LineHeight = TTF.FontLineSkip(Handle);
                    Loaded     = true;
                }
                else
                {
                    throw new FileLoadException(SDL.GetError());
                }
            }
        }
Beispiel #8
0
        public void Draw(string str, Point pos, Color color, Alignment alignment = Alignment.TopLeft, int depth = 0)
        {
            if (!Loaded)
            {
                throw new NotLoadedException();
            }

            //replace tab with 4 spaces because sdl_ttf doesn't
            str = str.Replace("\t", "    ");

            //create rows by splitting on newline character
            string[] rows        = str.Split('\n');
            IntPtr[] rowTextures = new IntPtr[rows.Length];

            //add independent drawjob for each line
            for (int i = 0; i < rows.Length; i++)
            {
                //leave blank if there's no use for a texture there (whitespace)
                if (String.IsNullOrWhiteSpace(rows[i]))
                {
                    rowTextures[i] = IntPtr.Zero;
                    continue;
                }

                Tuple <string, Color> key = new Tuple <string, Color>(rows[i], color);
                if (Textures.ContainsKey(key))                 //use an already rendered texture
                {
                    rowTextures[i]           = Textures[key];
                    TexturesDrawsUnused[key] = 0;
                }
                else                 //generate a new texture
                {
                    IntPtr textSurface = TTF.RenderUTF8_Blended(Handle, rows[i], color);
                    rowTextures[i] = SDL.CreateTextureFromSurface(Game.RendererHandle, textSurface);
                    SDL.FreeSurface(textSurface);

                    Textures.Add(key, rowTextures[i]);
                    TexturesDrawsUnused.Add(key, 0);
                }

                uint format;
                int  access, w, h;
                SDL.QueryTexture(rowTextures[i], out format, out access, out w, out h);

                float horizontalOffset = 0f;
                float verticalOffset   = 0f;

                //horizontal alignment
                if (alignment.HasFlag(Alignment.Center))
                {
                    horizontalOffset = -w / 2f;
                }
                if (alignment.HasFlag(Alignment.Right))
                {
                    horizontalOffset = -w;
                }

                //vertical alignment
                if (alignment.HasFlag(Alignment.Top))
                {
                    verticalOffset = i * LineHeight;
                }
                if (alignment.HasFlag(Alignment.Middle))
                {
                    verticalOffset = -rows.Length * LineHeight / 2f + i * LineHeight;
                }
                if (alignment.HasFlag(Alignment.Bottom))
                {
                    verticalOffset = -rows.Length * LineHeight + i * LineHeight;
                }

                Point texturePos  = pos + new Point(horizontalOffset, verticalOffset);
                Point textureSize = new Point(w, h);

                DrawX.DrawJobs.Add(new TextureDrawJob(depth, new Rectangle(texturePos, textureSize), rowTextures[i], new Rectangle(Point.Zero, new Point(w, h)), new ComplexRectangle(texturePos, textureSize)));
            }
        }
Beispiel #9
0
        /// <summary>
        /// Wraps the string by adding newlines so that (if drawn) it never exceeds the maxWidth.
        /// Optionally stops after maxLines have been processed, trimming the newline character off that line.
        /// Using this method before rendering the text will ensure the text is only checked once per step instead of once per draw (which can make a big difference).
        /// <param name="charsTrimmed">Amount of chars trimmed from the end of the INPUT string.</param>
        /// </summary>
        public string WrapString(string str, float maxWidth, int maxLines, out int charsTrimmed)
        {
            if (maxWidth <= 0f)
            {
                throw new IndexOutOfRangeException("maxWidth must be positive and nonzero.");
            }

            if (maxLines < 1)
            {
                throw new IndexOutOfRangeException("maxLines has to be over 0. Leave the argument out or use int.MaxValue to make the method (semi-)ignore the argument.");
            }

            string result = "", lineRemainder = "";
            int    lines = 0, lineStart = 0, lineLength = 0, w, h, length, newlinePos;

            charsTrimmed = 0;

            //replace tab with 4 spaces because sdl_ttf doesn't
            str = str.Replace("\t", "    ");

            while (lineStart + lineLength < str.Length)
            {
                lineStart = lineStart + lineLength;

                //calculate new line length (length til and including next newline)
                newlinePos = str.IndexOf('\n', lineStart);
                if (newlinePos != -1)
                {
                    lineLength = newlinePos + 1 - lineStart;
                }
                else
                {
                    lineLength = str.Length - lineStart;
                }

                lineRemainder = str.Substring(lineStart, lineLength);

                while (lineRemainder != "" && lines < maxLines)
                {
                    //check if the string fits initially, because then there would be no situation right?
                    TTF.SizeUTF8(Handle, lineRemainder, out w, out h);
                    if (w < maxWidth)
                    {
                        //will be trimmed later and it's easier to detect here (because the newline could be added by wrapping too)
                        if (++lines == maxLines && lineRemainder[lineRemainder.Length - 1] == '\n')
                        {
                            charsTrimmed++;
                        }

                        result       += lineRemainder;
                        lineRemainder = "";
                    }
                    else
                    {
                        //get closest fitting multiple of ten and add as many of those to the substring length as possible to reduce the amount of SizeUTF8 calls
                        length = 0;
                        for (int chunkLength = (int)Math.Pow(10, Math.Floor(Math.Log10(lineRemainder.Length))); chunkLength >= 1; chunkLength = chunkLength / 10)
                        {
                            w = 0;
                            while (w < maxWidth)
                            {
                                length += chunkLength;

                                //would be invalid to insert into upcoming substring call
                                if (length > lineRemainder.Length)
                                {
                                    break;
                                }

                                TTF.SizeUTF8(Handle, lineRemainder.Substring(0, length), out w, out h);
                            }

                            //revert last addition
                            length -= chunkLength;
                        }

                        //if length still is zero the character would be pushed back till the line limit, which is not desirable
                        if (length <= 0)
                        {
                            break;
                        }

                        result       += lineRemainder.Substring(0, length) + '\n';
                        lineRemainder = lineRemainder.Substring(length);

                        if (++lines == maxLines)
                        {
                            break;
                        }
                    }
                }

                if (lines == maxLines)
                {
                    break;
                }
            }

            //last line cannot end with newline
            if (lines == maxLines && result[result.Length - 1] == '\n')
            {
                result = result.Remove(result.Length - 1);
            }

            charsTrimmed += str.Substring(lineStart + lineLength).Length + lineRemainder.Length;

            return(result);
        }
Beispiel #10
0
        /// <summary>
        /// Sets up a window and enters the gameloop. (Code after this call won't run until the game has exited.)
        /// </summary>
        public static void Run(float speed = 100f)
        {
            SDL.Init(SDL.InitFlags.EVERYTHING);
            IMG.Init(IMG.InitFlags.EVERYTHING);
            Mix.Init(Mix.InitFlags.EVERYTHING);
            TTF.Init();

            //open window
            SDL.SetHint(SDL.HINT_RENDER_VSYNC, "1");
            SDL.SetHint(SDL.HINT_RENDER_SCALE_QUALITY, "2");

            WindowHandle   = SDL.CreateWindow("HatlessEngine", SDL.WINDOWPOS_UNDEFINED, SDL.WINDOWPOS_UNDEFINED, 800, 600, SDL.WindowFlags.WINDOW_SHOWN | SDL.WindowFlags.WINDOW_RESIZABLE | SDL.WindowFlags.WINDOW_INPUT_FOCUS);
            RendererHandle = SDL.CreateRenderer(WindowHandle, -1, (uint)(SDL.RendererFlags.RENDERER_ACCELERATED | SDL.RendererFlags.RENDERER_PRESENTVSYNC));
            SDL.SetRenderDrawBlendMode(RendererHandle, SDL.BlendMode.BLENDMODE_BLEND);

            Window.SetIcon();

            //add default view that spans the current window
            new View("default", new Rectangle(Point.Zero, Window.Size), new Rectangle(Point.Zero, new Point(1f, 1f)));

            //initialize audio system and let Resources handle sound expiration
            Mix.OpenAudio(44100, SDL.AUDIO_S16SYS, 2, 4096);
            Mix.AllocateChannels((int)(speed * 2));             //might want to dynamically create and remove channels during runtime
            Mix.ChannelFinished(new Mix.ChannelFinishedDelegate(Resources.SoundChannelFinished));
            Mix.HookMusicFinished(new Mix.MusicFinishedDelegate(Resources.MusicFinished));

            //initialize loop
            StepsPerSecond = speed;

            Running = true;

            if (Started != null)
            {
                Started(null, EventArgs.Empty);
            }

            Stopwatch stopWatch = new Stopwatch();

            stopWatch.Start();

            //do a step before the first draw can occur
            Step();

            long lastStepTick = 0;
            long lastDrawTick = 0;
            long lastStepTime = 0;
            long lastDrawTime = 0;

            while (Running)
            {
                //perform step when needed
                if (stopWatch.ElapsedTicks >= lastStepTick + TicksPerStep)
                {
                    if (CatchUpSteps)
                    {
                        lastStepTick = lastStepTick + TicksPerStep;
                    }
                    else
                    {
                        lastStepTick = stopWatch.ElapsedTicks;
                    }
                    Step();

                    _ActualSPS   = (int)(Stopwatch.Frequency / (stopWatch.ElapsedTicks - lastStepTime));
                    lastStepTime = stopWatch.ElapsedTicks;
                }

                //perform draw when ready for a new one
                if (!RenderframeReady && Running && stopWatch.ElapsedTicks >= lastDrawTick + TicksPerDraw)
                {
                    lastDrawTick = lastDrawTick + TicksPerDraw;
                    Draw();

                    _ActualFPS   = (int)(Stopwatch.Frequency / (stopWatch.ElapsedTicks - lastDrawTime));
                    lastDrawTime = stopWatch.ElapsedTicks;
                }
            }

            //cleanup and uninitialization
            Resources.UnloadAllExternalResources();
            Log.CloseAllStreams();
            Input.CloseGamepads();

            SDL.DestroyWindow(WindowHandle);
            WindowHandle = IntPtr.Zero;
            SDL.DestroyRenderer(RendererHandle);
            RendererHandle = IntPtr.Zero;

            Mix.CloseAudio();

            SDL.Quit();
            IMG.Quit();
            Mix.Quit();
            TTF.Quit();
        }
Beispiel #11
0
        static void Main(string[] args)
        {
            SDL.Init(InitFlags.Everything);
            Log.Priorities.SetAll(LogPriority.Verbose);
            Log.OutputFunction = (cat, prio, msg) => {
                Console.WriteLine($"[{prio}] {cat}: {msg}");
            };
            Log.Message(LogCategory.Application, LogPriority.Debug, "Foo and bar!?");
            TTF.Init();
            Events.Watch += (ref Event e) =>
            {
                //Console.WriteLine(e.ToString());
            };

            Console.WriteLine("Registering timer");
            int         callbackCount = 0;
            IDisposable?d             = null;

            d = SDLSharp.Timer.AddTimer(500, n =>
            {
                Console.WriteLine($"{n}: Timer callback {callbackCount++}");
                if (callbackCount > 4 && d != null)
                {
                    Console.WriteLine("I've had it with this callback business!");
                    d.Dispose();
                }
                return(500 * (uint)callbackCount);
            });
            Console.WriteLine($"{d} registered");

            Console.WriteLine("Ok, here we go:");


            Console.WriteLine($"Running SDL version {SDL.RuntimeVersion} {SDL.RuntimeRevision} {SDL.RuntimeRevisionNumber}");
            Console.WriteLine($"\tSDL_image version {Image.RuntimeVersion}");
            Console.WriteLine($"\tSDL_ttf version {TTF.RuntimeVersion}");
            Console.WriteLine($"Video drivers: {string.Join("; ", Video.Drivers)}");
            Console.WriteLine($"Audio drivers: {string.Join("; ", Audio.Drivers)}");
            Console.WriteLine($"Audio input devices: {string.Join("; ", Audio.InputDevices)}");
            Console.WriteLine($"Audio output devices: {string.Join("; ", Audio.InputDevices)}");

            if (Clipboard.HasText())
            {
                Console.Write("Clipboard contains: ");
                Console.WriteLine(Clipboard.GetText());
            }
            else
            {
                Console.Write("Clipboard is empty. An empty string looks like: ");
                Console.WriteLine(Clipboard.GetText());
            }

            foreach (var display in Video.Displays)
            {
                Console.WriteLine($"Display {display.Index}");
                Console.WriteLine($"    Name={display.Name}");
                Console.WriteLine($"    Bounds={display.Bounds}");
                Console.WriteLine($"    UsableBounds={display.UsableBounds}");
                Console.WriteLine($"    DPI={display.DPI}");
                Console.WriteLine($"    Modes.Current={display.Modes.Current}");
                Console.WriteLine($"    Modes.Desktop={display.Modes.Desktop}");
                for (int i = 0; i < display.Modes.Count; ++i)
                {
                    Console.WriteLine($"    Modes.[{i}]={display.Modes[i]}");
                }
            }
            for (int i = 0; i < Renderer.Drivers.Count; ++i)
            {
                var ri = Renderer.Drivers[i];
                Console.WriteLine($"Render driver {i}");
                Console.WriteLine($"    Name={ri.Name}");
                Console.WriteLine($"    Flags={ri.Flags}");
                Console.WriteLine($"    MaxTextureWidth={ri.MaxTextureWidth}");
                Console.WriteLine($"    MaxTextureHeight={ri.MaxTextureHeight}");
                for (int j = 0; j < ri.Formats.Count; ++j)
                {
                    Console.WriteLine($"    Formats.[{j}]={PixelFormat.GetName(ri.Formats[j])}");
                }
            }

            foreach (var joy in Joystick.Devices)
            {
                Console.WriteLine($"{joy}");
                Console.WriteLine($"\tGuid={joy.Guid}");
                Console.WriteLine($"\tName={joy.Name}");
                Console.WriteLine($"\tIsController={joy.IsController}");
                using (var j = joy.Open())
                {
                    Console.WriteLine($"\t\tOpened {j}");
                    Console.WriteLine($"\t\tID={j.ID}");
                    Console.WriteLine($"\t\tName={j.Name}");
                    Console.WriteLine($"\t\tGuid={j.Guid}");
                    Console.WriteLine($"\t\tPowerLevel={j.PowerLevel}");
                    Console.WriteLine($"\t\tNumAxes={j.Axes.Count}");
                    Console.WriteLine($"\t\tButtons={j.Buttons.Count}");
                    Console.WriteLine($"\t\tHats={j.Hats.Count}");
                    Console.WriteLine($"\t\tBalls={j.Balls.Count}");
                }

                if (joy.IsController)
                {
                    using (var c = joy.OpenController())
                    {
                        foreach (var axis in Enum.GetValues(typeof(GameControllerAxis)).Cast <GameControllerAxis>())
                        {
                            if (axis == GameControllerAxis.Invalid || axis == GameControllerAxis.Max)
                            {
                                continue;
                            }

                            var b = c.Axes.GetBind(axis);
                            Console.WriteLine($"\t\tAxis[{axis}/{GameController.AxisName(axis)}].Bind={b}");
                        }
                        foreach (var btn in Enum.GetValues(typeof(GameControllerButton)).Cast <GameControllerButton>())
                        {
                            if (btn == GameControllerButton.Invalid || btn == GameControllerButton.Max)
                            {
                                continue;
                            }
                            var b = c.Buttons.GetBind(btn);
                            Console.WriteLine($"\t\tButtons[{btn}/{GameController.ButtonName(btn)}].Bind={b}");
                        }
                        Console.WriteLine($"\t\tMapping={c.Mapping}");
                    }
                }
            }

            foreach (var dev in Audio.OutputDevices)
            {
                var fmt     = new AudioStreamFormat(44000, AudioDataFormat.Float32Bit, 1, 0, 1024);
                var changes = AllowedAudioStreamChange.Any;
                Console.Write($"Requesting {fmt} from audio output '{dev}' allowing changes to {changes}...");

                try
                {
                    using (var a = Audio.OpenOutput(dev, changes, fmt, out var obtained))
                    {
                        Console.WriteLine($"\tgot {obtained}");
                    }
                }
                catch (Exception ex)
                {
                    Console.WriteLine($"\tFailed w/ error: {ex}");
                }
            }


            foreach (var dev in Audio.InputDevices)
            {
                var fmt     = new AudioStreamFormat(44000, AudioDataFormat.Float32Bit, 1, 0, 1024);
                var changes = AllowedAudioStreamChange.Any;
                Console.Write($"Requesting {fmt} from audio input '{dev}' allowing changes to {changes}...");

                try
                {
                    using (var a = Audio.OpenInput(dev, changes, fmt, out var obtained))
                    {
                        Console.WriteLine($"\tgot {a} with format {obtained}");
                    }
                }
                catch (Exception ex)
                {
                    Console.WriteLine($"\tFailed w/ error: {ex}");
                }
            }

            Mixer.Open(44100, AudioDataFormat.Float32Bit, 2, 1024);
            Mixer.Init(MixerLoaders.MP3);

            Console.WriteLine($"Opened the mixer hz={Mixer.DeviceFrequency} f={Mixer.DeviceFormat} ch={Mixer.DeviceChannels}");
            Console.WriteLine($"\tAvailable music decoders {string.Join("; ", MusicTrack.Decoders)}");
            Console.WriteLine($"\tAvailable chunk decoders {string.Join("; ", MixerChunk.Decoders)}");


            PrintChannels();
            Mixer.Channels.Count = 8;
            PrintChannels();


            using var caketown = MusicTrack.Load("./assets/Caketown 1.mp3");
            Console.WriteLine($"Loaded {caketown}");
            Task.Run(async() =>
            {
                Mixer.Music.Play(caketown);

                Mixer.Music.Finished += (se, ev) => Console.WriteLine("Music finished");

                await Task.Delay(1000);
                Mixer.Music.Pause();
                Console.WriteLine($"{caketown} paused");
                await Task.Delay(1000);
                Mixer.Music.Resume();
                Console.WriteLine($"{caketown} resumed");
                await Task.Delay(1000);
                Mixer.Music.Rewind();
                Console.WriteLine($"{caketown} rewound");
                await Task.Delay(1000);
                Console.WriteLine($"{caketown} fading out");
                Mixer.Music.FadeOut(1000);
                Console.WriteLine($"{caketown} faded out");
                Mixer.Music.Halt();
                Console.WriteLine($"{caketown} halted");
            });

            using var alarm = MixerChunk.Load("./assets/wobbleboxx.com/Rise01.wav");

            var flags = WindowFlags.Shown | WindowFlags.Resizable;

            using (var window = Video.CreateWindow("Foo änd bar", Window.UndefinedPosition, Window.UndefinedPosition, 600, 400, flags))
                using (var renderer = Renderer.Create(window, -1, RendererFlags.Accelerated))
                {
                    Console.WriteLine($"Created window {window}");

                    Mixer.Channels.ChannelFinished += (se, ev) => Console.WriteLine($"{ev.Channel} finished");
                    window.SetHitTest((Window w, in SDLSharp.Point p) =>
                    {
                        Console.WriteLine($"Hit test at {(System.Drawing.Point)p} in window '{w}'");
                        Events.Current.Push((Action)(() =>
                        {
                            if (Mixer.Channels.Play(alarm, 1))
                            {
                                Console.Write("Playing sound ");
                            }
                            else
                            {
                                Console.Write("NOT playing sound ");
                            }
                            PrintChannels();
                        }));
                        return(HitTestResult.Normal);
                    });