From bd2530b615741d9709204b29543f94f5f17c8435 Mon Sep 17 00:00:00 2001 From: Kapendev Date: Wed, 14 Aug 2024 08:55:56 +0300 Subject: [PATCH] Added audio support. --- source/popka/engine.d | 94 ++++++++++++++++++++++++++++++++-- source/popka/types.d | 114 ++++++++++++++++++++++++++++++++++++++---- 2 files changed, 193 insertions(+), 15 deletions(-) diff --git a/source/popka/engine.d b/source/popka/engine.d index d2962f3..43db3b1 100644 --- a/source/popka/engine.d +++ b/source/popka/engine.d @@ -106,14 +106,27 @@ Result!Viewport loadViewport(int width, int height) { return Result!Viewport(value, value.isEmpty.toFault()); } -@trusted /// Loads a font file (TTF) from the assets folder. /// Can handle both forward slashes and backslashes in file paths. +@trusted Result!Font loadFont(IStr path, uint size, const(dchar)[] runes = []) { - auto value = ray.LoadFontEx(path.toAssetsPath.toCStr().unwrapOr(), size, cast(int*) runes.ptr, cast(int) runes.length).toPopka(); + auto value = ray.LoadFontEx(path.toAssetsPath().toCStr().unwrapOr(), size, cast(int*) runes.ptr, cast(int) runes.length).toPopka(); return Result!Font(value, value.isEmpty.toFault(Fault.cantFind)); } +/// Loads a audio file (WAV, OGG, MP3) from the assets folder. +/// Can handle both forward slashes and backslashes in file paths. +@trusted +Result!Audio loadAudio(IStr path) { + auto value = Audio(); + if (path.endsWith(".wav")) { + value.data = ray.LoadSound(path.toAssetsPath().toCStr().unwrapOr()); + } else { + value.data = ray.LoadMusicStream(path.toAssetsPath().toCStr().unwrapOr()); + } + return Result!Audio(value, value.isEmpty.toFault(Fault.cantFind)); +} + /// Saves a text file to the assets folder. /// Can handle both forward slashes and backslashes in file paths. Fault saveText(IStr path, IStr text) { @@ -245,8 +258,18 @@ void closeWindow() { } /// Sets the window background color to the given color. -void setBackgroundColor(Color color) { - engineState.backgroundColor = color; +void setBackgroundColor(Color value) { + engineState.backgroundColor = value; +} + +@trusted +void setMasterVolume(float value) { + ray.SetMasterVolume(value); +} + +@trusted +float masterVolume() { + return ray.GetMasterVolume(); } /// Returns true if the FPS is locked. @@ -596,6 +619,69 @@ Vec2 wasd() { return result; } +@trusted +void playAudio(Audio audio) { + if (audio.isEmpty) { + return; + } + + if (audio.isSound) { + ray.PlaySound(audio.sound); + } else { + ray.PlayMusicStream(audio.music); + } +} + +@trusted +void updateAudio(Audio audio) { + if (audio.isEmpty) { + return; + } + + if (audio.isMusic) { + ray.UpdateMusicStream(audio.music); + } +} + +@trusted +void pauseAudio(Audio audio) { + if (audio.isEmpty) { + return; + } + + if (audio.isSound) { + ray.PauseSound(audio.sound); + } else { + ray.PauseMusicStream(audio.music); + } +} + +@trusted +void resumeAudio(Audio audio) { + if (audio.isEmpty) { + return; + } + + if (audio.isSound) { + ray.ResumeSound(audio.sound); + } else { + ray.ResumeMusicStream(audio.music); + } +} + +@trusted +void stopAudio(Audio audio) { + if (audio.isEmpty) { + return; + } + + if (audio.isSound) { + ray.StopSound(audio.sound); + } else { + ray.StopMusicStream(audio.music); + } +} + @trusted void drawRect(Rect area, Color color = white) { if (isPixelPerfect) { diff --git a/source/popka/types.d b/source/popka/types.d index 793ad7f..ab9e6b3 100644 --- a/source/popka/types.d +++ b/source/popka/types.d @@ -17,7 +17,7 @@ public import joka; EngineState engineState; /// A type representing flipping orientations. -enum Flip { +enum Flip : ubyte { none, /// No flipping. x, /// Flipped along the X-axis. y, /// Flipped along the Y-axis. @@ -25,7 +25,7 @@ enum Flip { } /// A type representing texture filtering modes. -enum Filter { +enum Filter : ubyte { nearest, /// Nearest neighbor filtering (blocky). linear, /// Bilinear filtering (smooth). } @@ -256,10 +256,10 @@ struct Texture { /// Set the filter mode of the texture. @trusted - void setFilter(Filter filter) { + void setFilter(Filter value) { if (isEmpty) return; - this.filter = filter; - ray.SetTextureFilter(data, filter.toRay()); + filter = value; + ray.SetTextureFilter(data, value.toRay()); } /// Frees the loaded image. @@ -302,10 +302,10 @@ struct Viewport { /// Set the filter mode of the viewport. @trusted - void setFilter(Filter filter) { + void setFilter(Filter value) { if (isEmpty) return; - this.filter = filter; - ray.SetTextureFilter(data.texture, filter.toRay()); + filter = value; + ray.SetTextureFilter(data.texture, value.toRay()); } @trusted @@ -338,10 +338,10 @@ struct Font { /// Set the filter mode of the font. @trusted - void setFilter(Filter filter) { + void setFilter(Filter value) { if (isEmpty) return; - this.filter = filter; - ray.SetTextureFilter(data.texture, filter.toRay()); + filter = value; + ray.SetTextureFilter(data.texture, value.toRay()); } @trusted @@ -354,6 +354,98 @@ struct Font { } } +struct Audio { + Data data; + + alias Sound = ray.Sound; + alias Music = ray.Music; + alias Data = Variant!(Sound, Music); + + @safe @nogc nothrow: + + Sound sound() { + return data.get!Sound(); + } + + Music music() { + return data.get!Music(); + } + + bool isSound() { + return data.isKind!Sound; + } + + bool isMusic() { + return data.isKind!Music; + } + + bool isEmpty() { + if (isSound) { + return sound.stream.sampleRate == 0; + } else { + return music.stream.sampleRate == 0; + } + } + + @trusted + float time() { + if (isSound) { + return 0.0f; + } else { + return ray.GetMusicTimePlayed(music); + } + } + + @trusted + float waitTime() { + if (isSound) { + return 0.0f; + } else { + return ray.GetMusicTimeLength(music); + } + } + + @trusted + void setVolume(float value) { + if (isSound) { + ray.SetSoundVolume(sound, value); + } else { + ray.SetMusicVolume(music, value); + } + } + + @trusted + void setPitch(float value) { + if (isSound) { + ray.SetSoundPitch(sound, value); + } else { + ray.SetMusicPitch(music, value); + } + } + + @trusted + void setPan(float value) { + if (isSound) { + ray.SetSoundPan(sound, value); + } else { + ray.SetMusicPan(music, value); + } + } + + @trusted + void free() { + if (isEmpty) { + return; + } + if (isSound) { + ray.UnloadSound(sound); + } else { + ray.UnloadMusicStream(music); + } + this = Audio(); + } +} + /// Converts a raylib color to a Popka color. Color toPopka(ray.Color from) { return Color(from.r, from.g, from.b, from.a);