diff --git a/include/AudioDevice.hpp b/include/AudioDevice.hpp index bb475a39..6ad7f2ae 100644 --- a/include/AudioDevice.hpp +++ b/include/AudioDevice.hpp @@ -24,6 +24,9 @@ class AudioDevice { } } + AudioDevice(const AudioDevice&) = delete; + AudioDevice& operator=(const AudioDevice&) = delete; + /** * Close the audio device and context. */ diff --git a/include/AudioStream.hpp b/include/AudioStream.hpp index a9c8a4ee..4fa37202 100644 --- a/include/AudioStream.hpp +++ b/include/AudioStream.hpp @@ -1,45 +1,25 @@ #ifndef RAYLIB_CPP_INCLUDE_AUDIOSTREAM_HPP_ #define RAYLIB_CPP_INCLUDE_AUDIOSTREAM_HPP_ -#include "./RaylibException.hpp" -#include "./raylib-cpp-utils.hpp" -#include "./raylib.hpp" +#include "./AudioStreamUnmanaged.hpp" namespace raylib { /** - * AudioStream management functions + * AudioStream management functions. + * + * The audio stream will be unloaded on object destruction. Use raylib::AudioStreamUnmanaged if you're looking to not unload. + * + * @see raylib::AudioStreamUnmanaged */ -class AudioStream : public ::AudioStream { +class AudioStream : public AudioStreamUnmanaged { public: - AudioStream(const ::AudioStream& music) - : ::AudioStream(music) { - // Nothing. - } - - AudioStream( - rAudioBuffer* buffer = nullptr, - rAudioProcessor* processor = nullptr, - unsigned int sampleRate = 0, - unsigned int sampleSize = 0, - unsigned int channels = 0) - : ::AudioStream{buffer, processor, sampleRate, sampleSize, channels} { - // Nothing. - } - - /** - * Init audio stream (to stream raw audio pcm data) - * - * @throws raylib::RaylibException Throws if the AudioStream failed to load. - */ - AudioStream(unsigned int sampleRate, unsigned int sampleSize, unsigned int channels = 2) { - Load(sampleRate, sampleSize, channels); - } + using AudioStreamUnmanaged::AudioStreamUnmanaged; AudioStream(const AudioStream&) = delete; + AudioStream& operator=(const AudioStream&) = delete; AudioStream(AudioStream&& other) noexcept { set(other); - other.buffer = nullptr; other.processor = nullptr; other.sampleRate = 0; @@ -47,165 +27,25 @@ class AudioStream : public ::AudioStream { other.channels = 0; } - ~AudioStream() { Unload(); } - - GETTER(rAudioBuffer*, Buffer, buffer) - GETTER(rAudioProcessor*, Processor, processor) - GETTER(unsigned int, SampleRate, sampleRate) - GETTER(unsigned int, SampleSize, sampleSize) - GETTER(unsigned int, Channels, channels) - - AudioStream& operator=(const ::AudioStream& stream) { - set(stream); - return *this; - } - - AudioStream& operator=(const AudioStream&) = delete; - AudioStream& operator=(AudioStream&& other) noexcept { if (this == &other) { return *this; } - Unload(); set(other); - other.buffer = nullptr; other.processor = nullptr; other.sampleRate = 0; other.sampleSize = 0; other.channels = 0; - - return *this; - } - - /** - * Update audio stream buffers with data - */ - AudioStream& Update(const void* data, int samplesCount) { - ::UpdateAudioStream(*this, data, samplesCount); - return *this; - } - - /** - * Unload audio stream and free memory - */ - void Unload() { - if (IsValid()) { - ::UnloadAudioStream(*this); - } - } - - /** - * Check if any audio stream buffers requires refill - */ - [[nodiscard]] bool IsProcessed() const { return ::IsAudioStreamProcessed(*this); } - - /** - * Play audio stream - */ - AudioStream& Play() { - ::PlayAudioStream(*this); - return *this; - } - - /** - * Pause audio stream - */ - AudioStream& Pause() { - ::PauseAudioStream(*this); - return *this; - } - - /** - * Resume audio stream - */ - AudioStream& Resume() { - ::ResumeAudioStream(*this); - return *this; - } - - /** - * Check if audio stream is playing - */ - [[nodiscard]] bool IsPlaying() const { return ::IsAudioStreamPlaying(*this); } - - /** - * Stop audio stream - */ - AudioStream& Stop() { - ::StopAudioStream(*this); - return *this; - } - - /** - * Set volume for audio stream (1.0 is max level) - */ - AudioStream& SetVolume(float volume = 1.0f) { - ::SetAudioStreamVolume(*this, volume); return *this; } - /** - * Set pitch for audio stream (1.0 is base level) - */ - AudioStream& SetPitch(float pitch) { - ::SetAudioStreamPitch(*this, pitch); - return *this; - } - - /** - * Set pan for audio stream (0.5 is centered) - */ - AudioStream& SetPan(float pan = 0.5f) { - ::SetAudioStreamPan(*this, pan); - return *this; - } - - /** - * Default size for new audio streams - */ - static void SetBufferSizeDefault(int size) { ::SetAudioStreamBufferSizeDefault(size); } - - /** - * Audio thread callback to request new data - */ - void SetCallback(::AudioCallback callback) { ::SetAudioStreamCallback(*this, callback); } - - /** - * Attach audio stream processor to stream - */ - void AttachProcessor(::AudioCallback processor) { ::AttachAudioStreamProcessor(*this, processor); } - - /** - * Detach audio stream processor from stream - */ - void DetachProcessor(::AudioCallback processor) { ::DetachAudioStreamProcessor(*this, processor); } - - /** - * Retrieve whether or not the audio stream is ready. - */ - [[nodiscard]] bool IsValid() const { return ::IsAudioStreamValid(*this); } + ~AudioStream() { Unload(); } - /** - * Load audio stream (to stream raw audio pcm data) - * - * @throws raylib::RaylibException Throws if the AudioStream failed to load. - */ - void Load(unsigned int SampleRate, unsigned int SampleSize, unsigned int Channels = 2) { + void Load(unsigned int sampleRate, unsigned int sampleSize, unsigned int channels = 2) { Unload(); - set(::LoadAudioStream(SampleRate, SampleSize, Channels)); - if (!IsValid()) { - throw RaylibException("Failed to load audio stream"); - } - } -protected: - void set(const ::AudioStream& stream) { - buffer = stream.buffer; - processor = stream.processor; - sampleRate = stream.sampleRate; - sampleSize = stream.sampleSize; - channels = stream.channels; + AudioStreamUnmanaged::Load(sampleRate, sampleSize, channels); } }; } // namespace raylib diff --git a/include/AudioStreamUnmanaged.hpp b/include/AudioStreamUnmanaged.hpp new file mode 100644 index 00000000..97319264 --- /dev/null +++ b/include/AudioStreamUnmanaged.hpp @@ -0,0 +1,200 @@ +#ifndef RAYLIB_CPP_INCLUDE_AUDIOSTREAMUNMANAGED_HPP_ +#define RAYLIB_CPP_INCLUDE_AUDIOSTREAMUNMANAGED_HPP_ + +#include "./RaylibException.hpp" +#include "./raylib-cpp-utils.hpp" +#include "./raylib.hpp" + +namespace raylib { +/** + * An AudioStream that is not managed by C++ RAII. + * + * Make sure to Unload() this if needed, otherwise use raylib::AudioStream. + * + * @see raylib::AudioStream + */ +class AudioStreamUnmanaged : public ::AudioStream { +public: + /** + * Creates an AudioStreamUnmanaged from an existing AudioStream struct. + */ + AudioStreamUnmanaged(const ::AudioStream& stream) : ::AudioStream(stream) {} + + /** + * Creates an AudioStreamUnmanaged from its components. + */ + AudioStreamUnmanaged( + rAudioBuffer* buffer = nullptr, + rAudioProcessor* processor = nullptr, + unsigned int sampleRate = 0, + unsigned int sampleSize = 0, + unsigned int channels = 0) + : ::AudioStream{buffer, processor, sampleRate, sampleSize, channels} {} + + /** + * Init audio stream (to stream raw audio PCM data). + * + * @throws raylib::RaylibException Throws if the AudioStream failed to load. + */ + AudioStreamUnmanaged(unsigned int sampleRate, unsigned int sampleSize, unsigned int channels = 2) { + Load(sampleRate, sampleSize, channels); + } + + GETTER(rAudioBuffer*, Buffer, buffer) + GETTER(rAudioProcessor*, Processor, processor) + GETTER(unsigned int, SampleRate, sampleRate) + GETTER(unsigned int, SampleSize, sampleSize) + GETTER(unsigned int, Channels, channels) + + AudioStreamUnmanaged& operator=(const ::AudioStream& stream) { + set(stream); + return *this; + } + + /** + * Load audio stream (to stream raw audio PCM data). + * + * Does NOT call Unload() first — that is the responsibility of the managed class. + * + * @throws raylib::RaylibException Throws if the AudioStream failed to load. + */ + void Load(unsigned int sampleRate, unsigned int sampleSize, unsigned int channels = 2) { + set(::LoadAudioStream(sampleRate, sampleSize, channels)); + if (!IsValid()) { + throw RaylibException("Failed to load audio stream"); + } + } + + /** + * Unload audio stream and free memory. + */ + void Unload() { + // Protect against calling UnloadAudioStream() twice. + if (buffer != nullptr) { + ::UnloadAudioStream(*this); + buffer = nullptr; + } + } + + /** + * Update audio stream buffers with data. + */ + AudioStreamUnmanaged& Update(const void* data, int samplesCount) { + ::UpdateAudioStream(*this, data, samplesCount); + return *this; + } + + /** + * Check if any audio stream buffers require refill. + */ + [[nodiscard]] bool IsProcessed() const { return ::IsAudioStreamProcessed(*this); } + + /** + * Play audio stream. + */ + AudioStreamUnmanaged& Play() { + ::PlayAudioStream(*this); + return *this; + } + + /** + * Pause audio stream. + */ + AudioStreamUnmanaged& Pause() { + ::PauseAudioStream(*this); + return *this; + } + + /** + * Resume audio stream. + */ + AudioStreamUnmanaged& Resume() { + ::ResumeAudioStream(*this); + return *this; + } + + /** + * Check if audio stream is playing. + */ + [[nodiscard]] bool IsPlaying() const { return ::IsAudioStreamPlaying(*this); } + + /** + * Stop audio stream. + */ + AudioStreamUnmanaged& Stop() { + ::StopAudioStream(*this); + return *this; + } + + /** + * Set volume for audio stream (1.0 is max level). + */ + AudioStreamUnmanaged& SetVolume(float volume = 1.0f) { + ::SetAudioStreamVolume(*this, volume); + return *this; + } + + /** + * Set pitch for audio stream (1.0 is base level). + */ + AudioStreamUnmanaged& SetPitch(float pitch) { + ::SetAudioStreamPitch(*this, pitch); + return *this; + } + + /** + * Set pan for audio stream (0.5 is centered). + */ + AudioStreamUnmanaged& SetPan(float pan = 0.5f) { + ::SetAudioStreamPan(*this, pan); + return *this; + } + + /** + * Default size for new audio streams. + */ + static void SetBufferSizeDefault(int size) { ::SetAudioStreamBufferSizeDefault(size); } + + /** + * Audio thread callback to request new data. + */ + AudioStreamUnmanaged& SetCallback(::AudioCallback callback) { + ::SetAudioStreamCallback(*this, callback); + return *this; + } + + /** + * Attach audio stream processor to stream. + */ + AudioStreamUnmanaged& AttachProcessor(::AudioCallback processor) { + ::AttachAudioStreamProcessor(*this, processor); + return *this; + } + + /** + * Detach audio stream processor from stream. + */ + AudioStreamUnmanaged& DetachProcessor(::AudioCallback processor) { + ::DetachAudioStreamProcessor(*this, processor); + return *this; + } + + /** + * Retrieve whether or not the audio stream is ready. + */ + [[nodiscard]] bool IsValid() const { return ::IsAudioStreamValid(*this); } + +protected: + void set(const ::AudioStream& stream) { + buffer = stream.buffer; + processor = stream.processor; + sampleRate = stream.sampleRate; + sampleSize = stream.sampleSize; + channels = stream.channels; + } +}; +} // namespace raylib + +using RAudioStreamUnmanaged = raylib::AudioStreamUnmanaged; + +#endif // RAYLIB_CPP_INCLUDE_AUDIOSTREAMUNMANAGED_HPP_ diff --git a/include/Font.hpp b/include/Font.hpp index f70ebbff..b60ce546 100644 --- a/include/Font.hpp +++ b/include/Font.hpp @@ -1,92 +1,25 @@ #ifndef RAYLIB_CPP_INCLUDE_FONT_HPP_ #define RAYLIB_CPP_INCLUDE_FONT_HPP_ -#include - -#include "./RaylibException.hpp" -#include "./TextureUnmanaged.hpp" -#include "./raylib-cpp-utils.hpp" -#include "./raylib.hpp" +#include "./FontUnmanaged.hpp" namespace raylib { /** - * Font type, includes texture and charSet array data + * Font type, includes texture and charSet array data. + * + * The font will be unloaded on object destruction. Use raylib::FontUnmanaged if you're looking to not unload. + * + * @see raylib::FontUnmanaged */ -class Font : public ::Font { +class Font : public FontUnmanaged { public: - Font( - int baseSize, - int glyphCount, - int glyphPadding, - ::Texture2D texture, - ::Rectangle* recs = nullptr, - ::GlyphInfo* glyphs = nullptr) - : ::Font{baseSize, glyphCount, glyphPadding, texture, recs, glyphs} { - // Nothing. - } - - /** - * Retrieves the default Font. - */ - Font() : ::Font(::GetFontDefault()) { } - - Font(const ::Font& font) : ::Font(font) { } - - /** - * Loads a Font from the given file. - * - * @param fileName The file name of the font to load. - * - * @throws raylib::RaylibException Throws if the given font failed to initialize. - */ - Font(const std::string& fileName) { Load(fileName); } - - /** - * Loads a Font from the given file, with generation parameters. - * - * @param fileName The file name of the font to load. - * - * @throws raylib::RaylibException Throws if the given font failed to initialize. - * - * @see ::LoadFontEx - */ - Font(const std::string& fileName, int fontSize, const int* codepoints = nullptr, int codepointCount = 0) { - Load(fileName, fontSize, codepoints, codepointCount); - } - - /** - * Loads a Font from the given image with a color key. - * - * @param image The image to load the fond from. - * - * @throws raylib::RaylibException Throws if the given font failed to initialize. - * - * @see ::LoadFontFromImage() - */ - Font(const ::Image& image, ::Color key, int firstChar) { Load(image, key, firstChar); } - - /** - * Loads a font from memory, based on the given file type and file data. - * - * @throws raylib::RaylibException Throws if the given font failed to initialize. - * - * @see ::LoadFontFromMemory() - */ - Font( - const std::string& fileType, - const unsigned char* fileData, - int dataSize, - int fontSize, - const int* codepoints, - int codepointCount) { - Load(fileType, fileData, dataSize, fontSize, codepoints, codepointCount); - } + using FontUnmanaged::FontUnmanaged; Font(const Font&) = delete; + Font& operator=(const Font&) = delete; Font(Font&& other) noexcept { set(other); - other.baseSize = 0; other.glyphCount = 0; other.glyphPadding = 0; @@ -95,96 +28,42 @@ class Font : public ::Font { other.glyphs = nullptr; } - ~Font() { Unload(); } - - void Unload() { - // Protect against calling UnloadFont() twice. - if (baseSize != 0) { - UnloadFont(*this); - baseSize = 0; - } - } - - GETTER(int, BaseSize, baseSize) - GETTER(int, GlyphCount, glyphCount) - GETTER(int, GlyphPadding, glyphPadding) - GETTER(::Rectangle*, Recs, recs) - GETTER(::GlyphInfo*, Glyphs, glyphs) - - /** - * Get the texture atlas containing the glyphs. - */ - TextureUnmanaged GetTexture() { return texture; } - - /** - * Set the texture atlas containing the glyphs. - */ - void SetTexture(const ::Texture& newTexture) { texture = newTexture; } - - Font& operator=(const ::Font& font) { - Unload(); - set(font); - return *this; - } - - Font& operator=(const Font&) = delete; - Font& operator=(Font&& other) noexcept { if (this == &other) { return *this; } - Unload(); set(other); - other.baseSize = 0; other.glyphCount = 0; other.glyphPadding = 0; other.texture = {}; other.recs = nullptr; other.glyphs = nullptr; + return *this; + } + Font& operator=(const ::Font& font) { + Unload(); + set(font); return *this; } - /** - * Loads a font from a given file. - * - * @param fileName The filename of the font to load. - * - * @throws raylib::RaylibException Throws if the given font failed to initialize. - * - * @see ::LoadFont() - */ + ~Font() { Unload(); } + void Load(const std::string& fileName) { - set(::LoadFont(fileName.c_str())); - if (!IsValid()) { - throw RaylibException("Failed to load Font with from file: " + fileName); - } + Unload(); + FontUnmanaged::Load(fileName); } - /** - * Loads a font from a given file with generation parameters. - * - * @param fileName The filename of the font to load. - * @param fontSize The desired size of the font. - * - * @throws raylib::RaylibException Throws if the given font failed to initialize. - * - * @see ::LoadFontEx() - */ void Load(const std::string& fileName, int fontSize, const int* codepoints = nullptr, int codepointCount = 0) { - set(::LoadFontEx(fileName.c_str(), fontSize, codepoints, codepointCount)); - if (!IsValid()) { - throw RaylibException("Failed to load Font with from file with font size: " + fileName); - } + Unload(); + FontUnmanaged::Load(fileName, fontSize, codepoints, codepointCount); } void Load(const ::Image& image, ::Color key, int firstChar) { - set(::LoadFontFromImage(image, key, firstChar)); - if (!IsValid()) { - throw RaylibException("Failed to load Font with from image"); - } + Unload(); + FontUnmanaged::Load(image, key, firstChar); } void Load( @@ -194,135 +73,8 @@ class Font : public ::Font { int fontSize, const int* codepoints, int codepointCount) { - set(::LoadFontFromMemory(fileType.c_str(), fileData, dataSize, fontSize, codepoints, codepointCount)); - if (!IsValid()) { - throw RaylibException("Failed to load Font " + fileType + " with from file data"); - } - } - - /** - * Returns if the font is ready to be used. - */ - [[nodiscard]] bool IsValid() const { return ::IsFontValid(*this); } - - /** - * Draw text using font and additional parameters. - */ - void DrawText(const char* text, ::Vector2 position, float fontSize, float spacing, ::Color tint = WHITE) const { - ::DrawTextEx(*this, text, position, fontSize, spacing, tint); - } - - /** - * Draw text using font and additional parameters. - */ - void - DrawText(const std::string& text, ::Vector2 position, float fontSize, float spacing, ::Color tint = WHITE) const { - ::DrawTextEx(*this, text.c_str(), position, fontSize, spacing, tint); - } - - /** - * Draw text using font and additional parameters. - */ - void DrawText(const char* text, int posX, int posY, float fontSize, float spacing, ::Color tint = WHITE) const { - ::DrawTextEx(*this, text, {static_cast(posX), static_cast(posY)}, fontSize, spacing, tint); - } - - /** - * Draw text using font and additional parameters. - */ - void - DrawText(const std::string& text, int posX, int posY, float fontSize, float spacing, ::Color tint = WHITE) const { - ::DrawTextEx( - *this, - text.c_str(), - {static_cast(posX), static_cast(posY)}, - fontSize, - spacing, - tint); - } - - void DrawText( - const char* text, - ::Vector2 position, - ::Vector2 origin, - float rotation, - float fontSize, - float spacing, - ::Color tint = WHITE) const { - ::DrawTextPro(*this, text, position, origin, rotation, fontSize, spacing, tint); - } - - void DrawText( - const std::string& text, - ::Vector2 position, - ::Vector2 origin, - float rotation, - float fontSize, - float spacing, - ::Color tint = WHITE) const { - ::DrawTextPro(*this, text.c_str(), position, origin, rotation, fontSize, spacing, tint); - } - - /** - * Draw one character (codepoint) - */ - void DrawText(int codepoint, ::Vector2 position, float fontSize, ::Color tint = {255, 255, 255, 255}) const { - ::DrawTextCodepoint(*this, codepoint, position, fontSize, tint); - } - - /** - * Draw multiple character (codepoint) - */ - void DrawText( - const int* codepoints, - int count, - ::Vector2 position, - float fontSize, - float spacing, - ::Color tint = {255, 255, 255, 255}) const { - ::DrawTextCodepoints(*this, codepoints, count, position, fontSize, spacing, tint); - } - - /** - * Measure string size for Font - */ - [[nodiscard]] Vector2 MeasureText(const char* text, float fontSize, float spacing) const { - return ::MeasureTextEx(*this, text, fontSize, spacing); - } - - /** - * Measure string size for Font - */ - [[nodiscard]] Vector2 MeasureText(const std::string& text, float fontSize, float spacing) const { - return ::MeasureTextEx(*this, text.c_str(), fontSize, spacing); - } - - /** - * Get index position for a unicode character on font - */ - [[nodiscard]] int GetGlyphIndex(int character) const { return ::GetGlyphIndex(*this, character); } - - /** - * Create an image from text (custom sprite font) - */ - [[nodiscard]] ::Image ImageText(const char* text, float fontSize, float spacing, ::Color tint) const { - return ::ImageTextEx(*this, text, fontSize, spacing, tint); - } - - /** - * Create an image from text (custom sprite font) - */ - [[nodiscard]] ::Image ImageText(const std::string& text, float fontSize, float spacing, ::Color tint) const { - return ::ImageTextEx(*this, text.c_str(), fontSize, spacing, tint); - } -protected: - void set(const ::Font& font) { - baseSize = font.baseSize; - glyphCount = font.glyphCount; - glyphPadding = font.glyphPadding; - texture = font.texture; - recs = font.recs; - glyphs = font.glyphs; + Unload(); + FontUnmanaged::Load(fileType, fileData, dataSize, fontSize, codepoints, codepointCount); } }; } // namespace raylib diff --git a/include/FontUnmanaged.hpp b/include/FontUnmanaged.hpp new file mode 100644 index 00000000..c4caa029 --- /dev/null +++ b/include/FontUnmanaged.hpp @@ -0,0 +1,312 @@ +#ifndef RAYLIB_CPP_INCLUDE_FONTUNMANAGED_HPP_ +#define RAYLIB_CPP_INCLUDE_FONTUNMANAGED_HPP_ + +#include + +#include "./RaylibException.hpp" +#include "./TextureUnmanaged.hpp" +#include "./raylib-cpp-utils.hpp" +#include "./raylib.hpp" + +namespace raylib { +/** + * A Font that is not managed by C++ RAII. + * + * Make sure to Unload() this if needed, otherwise use raylib::Font. + * + * @see raylib::Font + */ +class FontUnmanaged : public ::Font { +public: + FontUnmanaged( + int baseSize, + int glyphCount, + int glyphPadding, + ::Texture2D texture, + ::Rectangle* recs = nullptr, + ::GlyphInfo* glyphs = nullptr) + : ::Font{baseSize, glyphCount, glyphPadding, texture, recs, glyphs} { + // Nothing. + } + + /** + * Retrieves the default Font. + */ + FontUnmanaged() : ::Font(::GetFontDefault()) {} + + /** + * Creates a FontUnmanaged from an existing Font struct. + */ + FontUnmanaged(const ::Font& font) : ::Font(font) {} + + /** + * Loads a Font from the given file. + * + * @throws raylib::RaylibException Throws if the given font failed to initialize. + */ + FontUnmanaged(const std::string& fileName) { Load(fileName); } + + /** + * Loads a Font from the given file, with generation parameters. + * + * @throws raylib::RaylibException Throws if the given font failed to initialize. + */ + FontUnmanaged(const std::string& fileName, int fontSize, const int* codepoints = nullptr, int codepointCount = 0) { + Load(fileName, fontSize, codepoints, codepointCount); + } + + /** + * Loads a Font from the given image with a color key. + * + * @throws raylib::RaylibException Throws if the given font failed to initialize. + */ + FontUnmanaged(const ::Image& image, ::Color key, int firstChar) { Load(image, key, firstChar); } + + /** + * Loads a font from memory, based on the given file type and file data. + * + * @throws raylib::RaylibException Throws if the given font failed to initialize. + */ + FontUnmanaged( + const std::string& fileType, + const unsigned char* fileData, + int dataSize, + int fontSize, + const int* codepoints, + int codepointCount) { + Load(fileType, fileData, dataSize, fontSize, codepoints, codepointCount); + } + + GETTER(int, BaseSize, baseSize) + GETTER(int, GlyphCount, glyphCount) + GETTER(int, GlyphPadding, glyphPadding) + GETTER(::Rectangle*, Recs, recs) + GETTER(::GlyphInfo*, Glyphs, glyphs) + + /** + * Get the texture atlas containing the glyphs. + */ + TextureUnmanaged GetTexture() { return texture; } + [[nodiscard]] TextureUnmanaged GetTexture() const { return texture; } + + /** + * Set the texture atlas containing the glyphs. + */ + void SetTexture(const ::Texture& newTexture) { texture = newTexture; } + + FontUnmanaged& operator=(const ::Font& font) { + set(font); + return *this; + } + + /** + * Loads a font from a given file. + * + * @throws raylib::RaylibException Throws if the given font failed to initialize. + */ + void Load(const std::string& fileName) { + set(::LoadFont(fileName.c_str())); + if (!IsValid()) { + throw RaylibException("Failed to load Font with from file: " + fileName); + } + } + + /** + * Loads a font from a given file with generation parameters. + * + * @throws raylib::RaylibException Throws if the given font failed to initialize. + */ + void Load(const std::string& fileName, int fontSize, const int* codepoints = nullptr, int codepointCount = 0) { + set(::LoadFontEx(fileName.c_str(), fontSize, codepoints, codepointCount)); + if (!IsValid()) { + throw RaylibException("Failed to load Font with from file with font size: " + fileName); + } + } + + /** + * Loads a font from an image with a color key. + * + * @throws raylib::RaylibException Throws if the given font failed to initialize. + */ + void Load(const ::Image& image, ::Color key, int firstChar) { + set(::LoadFontFromImage(image, key, firstChar)); + if (!IsValid()) { + throw RaylibException("Failed to load Font with from image"); + } + } + + /** + * Loads a font from memory. + * + * @throws raylib::RaylibException Throws if the given font failed to initialize. + */ + void Load( + const std::string& fileType, + const unsigned char* fileData, + int dataSize, + int fontSize, + const int* codepoints, + int codepointCount) { + set(::LoadFontFromMemory(fileType.c_str(), fileData, dataSize, fontSize, codepoints, codepointCount)); + if (!IsValid()) { + throw RaylibException("Failed to load Font " + fileType + " with from file data"); + } + } + + /** + * Unload font from memory. + */ + void Unload() { + // Protect against calling UnloadFont() twice. + if (baseSize != 0) { + ::UnloadFont(*this); + baseSize = 0; + } + } + + /** + * Returns if the font is ready to be used. + */ + [[nodiscard]] bool IsValid() const { return ::IsFontValid(*this); } + + /** + * Draw text using font and additional parameters. + */ + void DrawText(const char* text, ::Vector2 position, float fontSize, float spacing, ::Color tint = WHITE) const { + ::DrawTextEx(*this, text, position, fontSize, spacing, tint); + } + + /** + * Draw text using font and additional parameters. + */ + void DrawText( + const std::string& text, + ::Vector2 position, + float fontSize, + float spacing, + ::Color tint = WHITE) const { + ::DrawTextEx(*this, text.c_str(), position, fontSize, spacing, tint); + } + + /** + * Draw text using font and additional parameters. + */ + void DrawText(const char* text, int posX, int posY, float fontSize, float spacing, ::Color tint = WHITE) const { + ::DrawTextEx(*this, text, {static_cast(posX), static_cast(posY)}, fontSize, spacing, tint); + } + + /** + * Draw text using font and additional parameters. + */ + void DrawText( + const std::string& text, + int posX, + int posY, + float fontSize, + float spacing, + ::Color tint = WHITE) const { + ::DrawTextEx( + *this, + text.c_str(), + {static_cast(posX), static_cast(posY)}, + fontSize, + spacing, + tint); + } + + /** + * Draw text using font with pro parameters (rotation). + */ + void DrawText( + const char* text, + ::Vector2 position, + ::Vector2 origin, + float rotation, + float fontSize, + float spacing, + ::Color tint = WHITE) const { + ::DrawTextPro(*this, text, position, origin, rotation, fontSize, spacing, tint); + } + + /** + * Draw text using font with pro parameters (rotation). + */ + void DrawText( + const std::string& text, + ::Vector2 position, + ::Vector2 origin, + float rotation, + float fontSize, + float spacing, + ::Color tint = WHITE) const { + ::DrawTextPro(*this, text.c_str(), position, origin, rotation, fontSize, spacing, tint); + } + + /** + * Draw one character (codepoint). + */ + void DrawText(int codepoint, ::Vector2 position, float fontSize, ::Color tint = {255, 255, 255, 255}) const { + ::DrawTextCodepoint(*this, codepoint, position, fontSize, tint); + } + + /** + * Draw multiple characters (codepoints). + */ + void DrawText( + const int* codepoints, + int count, + ::Vector2 position, + float fontSize, + float spacing, + ::Color tint = {255, 255, 255, 255}) const { + ::DrawTextCodepoints(*this, codepoints, count, position, fontSize, spacing, tint); + } + + /** + * Measure string size for Font. + */ + [[nodiscard]] Vector2 MeasureText(const char* text, float fontSize, float spacing) const { + return ::MeasureTextEx(*this, text, fontSize, spacing); + } + + /** + * Measure string size for Font. + */ + [[nodiscard]] Vector2 MeasureText(const std::string& text, float fontSize, float spacing) const { + return ::MeasureTextEx(*this, text.c_str(), fontSize, spacing); + } + + /** + * Get index position for a unicode character on font. + */ + [[nodiscard]] int GetGlyphIndex(int character) const { return ::GetGlyphIndex(*this, character); } + + /** + * Create an image from text (custom sprite font). + */ + [[nodiscard]] ::Image ImageText(const char* text, float fontSize, float spacing, ::Color tint) const { + return ::ImageTextEx(*this, text, fontSize, spacing, tint); + } + + /** + * Create an image from text (custom sprite font). + */ + [[nodiscard]] ::Image ImageText(const std::string& text, float fontSize, float spacing, ::Color tint) const { + return ::ImageTextEx(*this, text.c_str(), fontSize, spacing, tint); + } + +protected: + void set(const ::Font& font) { + baseSize = font.baseSize; + glyphCount = font.glyphCount; + glyphPadding = font.glyphPadding; + texture = font.texture; + recs = font.recs; + glyphs = font.glyphs; + } +}; +} // namespace raylib + +using RFontUnmanaged = raylib::FontUnmanaged; + +#endif // RAYLIB_CPP_INCLUDE_FONTUNMANAGED_HPP_ diff --git a/include/Material.hpp b/include/Material.hpp index 97f47f01..2b6a27c8 100644 --- a/include/Material.hpp +++ b/include/Material.hpp @@ -1,30 +1,25 @@ #ifndef RAYLIB_CPP_INCLUDE_MATERIAL_HPP_ #define RAYLIB_CPP_INCLUDE_MATERIAL_HPP_ -#include -#include - -#include "./raylib-cpp-utils.hpp" -#include "./raylib.hpp" +#include "./MaterialUnmanaged.hpp" namespace raylib { /** - * Material type (generic) + * Material type (generic). + * + * The material will be unloaded on object destruction. Use raylib::MaterialUnmanaged if you're looking to not unload. + * + * @see raylib::MaterialUnmanaged */ -class Material : public ::Material { +class Material : public MaterialUnmanaged { public: - Material(const ::Material& material) : ::Material(material) { } - - /** - * Load default material (Supports: DIFFUSE, SPECULAR, NORMAL maps) - */ - Material() : ::Material(LoadMaterialDefault()) { } + using MaterialUnmanaged::MaterialUnmanaged; Material(const Material&) = delete; + Material& operator=(const Material&) = delete; Material(Material&& other) noexcept { set(other); - other.maps = nullptr; other.shader = {}; other.params[0] = 0.0f; @@ -33,87 +28,24 @@ class Material : public ::Material { other.params[3] = 0.0f; } - ~Material() { Unload(); } - - /** - * Load materials from model file - */ - static std::vector Load(const std::string& fileName) { - int count = 0; - // TODO(RobLoach): Material::Load() possibly leaks the materials array. - ::Material* materials = ::LoadMaterials(fileName.c_str(), &count); - return std::vector(materials, materials + count); - } - - GETTERSETTER(::Shader, Shader, shader) - GETTERSETTER(::MaterialMap*, Maps, maps) - // TODO(RobLoach): Resolve the Material params being a float[4]. - // GETTERSETTER(float[4], Params, params) - - Material& operator=(const ::Material& material) { - set(material); - return *this; - } - - Material& operator=(const Material&) = delete; - Material& operator=(Material&& other) noexcept { if (this == &other) { return *this; } - Unload(); set(other); - other.maps = nullptr; other.shader = {}; - return *this; } - /** - * Unload material from memory - */ - void Unload() { - if (maps != nullptr) { - ::UnloadMaterial(*this); - maps = nullptr; - } - } - - /** - * Set texture for a material map type (MAP_DIFFUSE, MAP_SPECULAR...) - */ - Material& SetTexture(int mapType, const ::Texture2D& texture) { - ::SetMaterialTexture(this, mapType, texture); + Material& operator=(const ::Material& material) { + Unload(); + set(material); return *this; } - /** - * Draw a 3d mesh with material and transform - */ - void DrawMesh(const ::Mesh& mesh, ::Matrix transform) const { ::DrawMesh(mesh, *this, transform); } - - /** - * Draw multiple mesh instances with material and different transforms - */ - void DrawMesh(const ::Mesh& mesh, ::Matrix* transforms, int instances) const { - ::DrawMeshInstanced(mesh, *this, transforms, instances); - } - - /** - * Check if material is ready - */ - [[nodiscard]] bool IsValid() const { return ::IsMaterialValid(*this); } -protected: - void set(const ::Material& material) { - shader = material.shader; - maps = material.maps; - params[0] = material.params[0]; - params[1] = material.params[1]; - params[2] = material.params[2]; - params[3] = material.params[3]; - } + ~Material() { Unload(); } }; } // namespace raylib diff --git a/include/MaterialUnmanaged.hpp b/include/MaterialUnmanaged.hpp new file mode 100644 index 00000000..3e0764c6 --- /dev/null +++ b/include/MaterialUnmanaged.hpp @@ -0,0 +1,96 @@ +#ifndef RAYLIB_CPP_INCLUDE_MATERIALUNMANAGED_HPP_ +#define RAYLIB_CPP_INCLUDE_MATERIALUNMANAGED_HPP_ + +#include +#include + +#include "./raylib-cpp-utils.hpp" +#include "./raylib.hpp" + +namespace raylib { +/** + * A Material that is not managed by C++ RAII. + * + * Make sure to Unload() this if needed, otherwise use raylib::Material. + * + * @see raylib::Material + */ +class MaterialUnmanaged : public ::Material { +public: + /** + * Creates a MaterialUnmanaged from an existing Material struct. + */ + MaterialUnmanaged(const ::Material& material) : ::Material(material) {} + + /** + * Load default material (Supports: DIFFUSE, SPECULAR, NORMAL maps). + */ + MaterialUnmanaged() : ::Material(::LoadMaterialDefault()) {} + + /** + * Load materials from model file. + */ + static std::vector Load(const std::string& fileName) { + int count = 0; + ::Material* mats = ::LoadMaterials(fileName.c_str(), &count); + return std::vector(mats, mats + count); + } + + GETTERSETTER(::Shader, Shader, shader) + GETTERSETTER(::MaterialMap*, Maps, maps) + + MaterialUnmanaged& operator=(const ::Material& material) { + set(material); + return *this; + } + + /** + * Unload material from memory. + */ + void Unload() { + if (maps != nullptr) { + ::UnloadMaterial(*this); + maps = nullptr; + } + } + + /** + * Set texture for a material map type (MAP_DIFFUSE, MAP_SPECULAR...). + */ + MaterialUnmanaged& SetTexture(int mapType, const ::Texture2D& texture) { + ::SetMaterialTexture(this, mapType, texture); + return *this; + } + + /** + * Draw a 3d mesh with material and transform. + */ + void DrawMesh(const ::Mesh& mesh, ::Matrix transform) const { ::DrawMesh(mesh, *this, transform); } + + /** + * Draw multiple mesh instances with material and different transforms. + */ + void DrawMesh(const ::Mesh& mesh, ::Matrix* transforms, int instances) const { + ::DrawMeshInstanced(mesh, *this, transforms, instances); + } + + /** + * Check if material is ready. + */ + [[nodiscard]] bool IsValid() const { return ::IsMaterialValid(*this); } + +protected: + void set(const ::Material& material) { + shader = material.shader; + maps = material.maps; + params[0] = material.params[0]; + params[1] = material.params[1]; + params[2] = material.params[2]; + params[3] = material.params[3]; + } +}; +} // namespace raylib + +using RMaterialUnmanaged = raylib::MaterialUnmanaged; + +#endif // RAYLIB_CPP_INCLUDE_MATERIALUNMANAGED_HPP_ diff --git a/include/MeshUnmanaged.hpp b/include/MeshUnmanaged.hpp index 09030e78..4fce20e2 100644 --- a/include/MeshUnmanaged.hpp +++ b/include/MeshUnmanaged.hpp @@ -208,7 +208,7 @@ class MeshUnmanaged : public ::Mesh { /** * Compute mesh tangents */ - Mesh& GenTangents() { + MeshUnmanaged& GenTangents() { ::GenMeshTangents(this); return *this; } diff --git a/include/Model.hpp b/include/Model.hpp index 15284668..9511bbcf 100644 --- a/include/Model.hpp +++ b/include/Model.hpp @@ -1,41 +1,20 @@ #ifndef RAYLIB_CPP_INCLUDE_MODEL_HPP_ #define RAYLIB_CPP_INCLUDE_MODEL_HPP_ -#include - -#include "./RaylibException.hpp" -#include "./raylib-cpp-utils.hpp" -#include "./raylib.hpp" +#include "./ModelUnmanaged.hpp" namespace raylib { class Mesh; /** - * Model type + * Model type. + * + * The model will be unloaded on object destruction. Use raylib::ModelUnmanaged if you're looking to not unload. + * + * @see raylib::ModelUnmanaged */ -class Model : public ::Model { +class Model : public ModelUnmanaged { public: - Model() { - // Nothing. - } - - /* - * Copy a model from another model. - */ - Model(const ::Model& model) : ::Model(model) { } - - /* - * Load a model from a file. - * - * @throws raylib::RaylibException Throws if failed to load the Modal. - */ - Model(const std::string& fileName) { Load(fileName); } - - /* - * Load a model from a mesh. - * - * @throws raylib::RaylibException Throws if failed to load the Modal. - */ - Model(const ::Mesh& mesh) { Load(mesh); } + using ModelUnmanaged::ModelUnmanaged; /** * The Model constructor with a Mesh() is removed. @@ -46,19 +25,16 @@ class Model : public ::Model { */ Model(const raylib::Mesh& mesh) = delete; - ~Model() { Unload(); } - Model(const Model&) = delete; + Model& operator=(const Model&) = delete; Model(Model&& other) noexcept { set(other); - other.meshCount = 0; other.materialCount = 0; other.meshes = nullptr; other.materials = nullptr; other.meshMaterial = nullptr; - other.skeleton.boneCount = 0; other.skeleton.bones = nullptr; other.skeleton.bindPose = nullptr; @@ -66,33 +42,12 @@ class Model : public ::Model { other.boneMatrices = nullptr; } - GETTERSETTER(::Matrix, Transform, transform) - GETTERSETTER(int, MeshCount, meshCount) - GETTERSETTER(int, MaterialCount, materialCount) - GETTERSETTER(::Mesh*, Meshes, meshes) - GETTERSETTER(::Material*, Materials, materials) - GETTERSETTER(int*, MeshMaterial, meshMaterial) - GETTERSETTER(int, BoneCount, skeleton.boneCount) - GETTERSETTER(::BoneInfo*, Bones, skeleton.bones) - GETTERSETTER(::Transform*, BindPose, skeleton.bindPose) - GETTERSETTER(::ModelAnimPose, CurrentPose, currentPose) - GETTERSETTER(::Matrix*, BoneMatrices, boneMatrices) - - Model& operator=(const ::Model& model) { - set(model); - return *this; - } - - Model& operator=(const Model&) = delete; - Model& operator=(Model&& other) noexcept { if (this == &other) { return *this; } - Unload(); set(other); - other.meshCount = 0; other.materialCount = 0; other.meshes = nullptr; @@ -103,144 +58,27 @@ class Model : public ::Model { other.skeleton.bindPose = nullptr; other.currentPose = nullptr; other.boneMatrices = nullptr; - - return *this; - } - - /** - * Unload model (including meshes) from memory (RAM and/or VRAM) - */ - void Unload() { - if (meshes != nullptr || materials != nullptr) { - ::UnloadModel(*this); - meshes = nullptr; - materials = nullptr; - } - } - - /** - * Set material for a mesh - */ - Model& SetMeshMaterial(int meshId, int materialId) { - ::SetModelMeshMaterial(this, meshId, materialId); return *this; } - /** - * Update model animation pose - */ - Model& UpdateAnimation(const ::ModelAnimation& anim, float frame) { - ::UpdateModelAnimation(*this, anim, frame); - return *this; - } - - /** - * Blend two model animation poses - */ - Model& BlendAnimation(const ::ModelAnimation& animA, float frameA, const ::ModelAnimation& animB, float frameB, float blend) { - ::UpdateModelAnimationEx(*this, animA, frameA, animB, frameB, blend); + Model& operator=(const ::Model& model) { + Unload(); + set(model); return *this; } - /** - * Check model animation skeleton match - */ - [[nodiscard]] bool IsModelAnimationValid(const ::ModelAnimation& anim) const { return ::IsModelAnimationValid(*this, anim); } - - /** - * Draw a model (with texture if set) - */ - void Draw(::Vector3 position, float scale = 1.0f, ::Color tint = {255, 255, 255, 255}) const { - ::DrawModel(*this, position, scale, tint); - } - - /** - * Draw a model with extended parameters - */ - void Draw( - ::Vector3 position, - ::Vector3 rotationAxis, - float rotationAngle = 0.0f, - ::Vector3 scale = {1.0f, 1.0f, 1.0f}, - ::Color tint = {255, 255, 255, 255}) const { - ::DrawModelEx(*this, position, rotationAxis, rotationAngle, scale, tint); - } - - /** - * Draw a model wires (with texture if set) - */ - void DrawWires(::Vector3 position, float scale = 1.0f, ::Color tint = {255, 255, 255, 255}) const { - ::DrawModelWires(*this, position, scale, tint); - } - - /** - * Draw a model wires (with texture if set) with extended parameters - */ - void DrawWires( - ::Vector3 position, - ::Vector3 rotationAxis, - float rotationAngle = 0.0f, - ::Vector3 scale = {1.0f, 1.0f, 1.0f}, - ::Color tint = {255, 255, 255, 255}) const { - ::DrawModelWiresEx(*this, position, rotationAxis, rotationAngle, scale, tint); - } - - /** - * Compute model bounding box limits (considers all meshes) - */ - [[nodiscard]] BoundingBox GetBoundingBox() const { return ::GetModelBoundingBox(*this); } - - /** - * Compute model bounding box limits (considers all meshes) - */ - explicit operator BoundingBox() const { return ::GetModelBoundingBox(*this); } - - /** - * Determines whether or not the Model has data in it. - */ - [[nodiscard]] bool IsValid() const { return ::IsModelValid(*this); } + ~Model() { Unload(); } - /** - * Loads a Model from the given file. - * - * @throws raylib::RaylibException Throws if failed to load the Modal. - */ void Load(const std::string& fileName) { - set(::LoadModel(fileName.c_str())); - if (!IsValid()) { - throw RaylibException("Failed to load Model from " + fileName); - } + Unload(); + ModelUnmanaged::Load(fileName); } - /** - * Loads a Model from the given Mesh. - * - * @throws raylib::RaylibException Throws if failed to load the Modal. - */ void Load(const ::Mesh& mesh) { - set(::LoadModelFromMesh(mesh)); - if (!IsValid()) { - throw RaylibException("Failed to load Model from Mesh"); - } - } -protected: - void set(const ::Model& model) { - transform = model.transform; - - meshCount = model.meshCount; - materialCount = model.materialCount; - meshes = model.meshes; - materials = model.materials; - meshMaterial = model.meshMaterial; - - skeleton.boneCount = model.skeleton.boneCount; - skeleton.bones = model.skeleton.bones; - skeleton.bindPose = model.skeleton.bindPose; - currentPose = model.currentPose; - boneMatrices = model.boneMatrices; + Unload(); + ModelUnmanaged::Load(mesh); } }; - } // namespace raylib using RModel = raylib::Model; diff --git a/include/ModelAnimation.hpp b/include/ModelAnimation.hpp index 6cbcd6a7..ba04d6d3 100644 --- a/include/ModelAnimation.hpp +++ b/include/ModelAnimation.hpp @@ -73,7 +73,10 @@ class ModelAnimation : public ::ModelAnimation { * Unload animation data */ void Unload() { - ::UnloadModelAnimations(this, 1); + if (keyframePoses != nullptr) { + ::UnloadModelAnimations(this, 1); + keyframePoses = nullptr; + } } static void Unload(ModelAnimation *modelAnimation, int count) { diff --git a/include/ModelUnmanaged.hpp b/include/ModelUnmanaged.hpp new file mode 100644 index 00000000..3c0cbd3b --- /dev/null +++ b/include/ModelUnmanaged.hpp @@ -0,0 +1,207 @@ +#ifndef RAYLIB_CPP_INCLUDE_MODELUNMANAGED_HPP_ +#define RAYLIB_CPP_INCLUDE_MODELUNMANAGED_HPP_ + +#include + +#include "./BoundingBox.hpp" +#include "./RaylibException.hpp" +#include "./raylib-cpp-utils.hpp" +#include "./raylib.hpp" + +namespace raylib { +/** + * A Model that is not managed by C++ RAII. + * + * Make sure to Unload() this if needed, otherwise use raylib::Model. + * + * @see raylib::Model + */ +class ModelUnmanaged : public ::Model { +public: + /** + * Default constructor. + */ + ModelUnmanaged() {} + + /** + * Creates a ModelUnmanaged from an existing Model struct. + */ + ModelUnmanaged(const ::Model& model) : ::Model(model) {} + + /** + * Loads a Model from the given file. + * + * @throws raylib::RaylibException Throws if failed to load the Model. + */ + ModelUnmanaged(const std::string& fileName) { Load(fileName); } + + /** + * Loads a Model from the given Mesh. + * + * @throws raylib::RaylibException Throws if failed to load the Model. + */ + ModelUnmanaged(const ::Mesh& mesh) { Load(mesh); } + + GETTERSETTER(::Matrix, Transform, transform) + GETTERSETTER(int, MeshCount, meshCount) + GETTERSETTER(int, MaterialCount, materialCount) + GETTERSETTER(::Mesh*, Meshes, meshes) + GETTERSETTER(::Material*, Materials, materials) + GETTERSETTER(int*, MeshMaterial, meshMaterial) + GETTERSETTER(int, BoneCount, skeleton.boneCount) + GETTERSETTER(::BoneInfo*, Bones, skeleton.bones) + GETTERSETTER(::Transform*, BindPose, skeleton.bindPose) + GETTERSETTER(::ModelAnimPose, CurrentPose, currentPose) + GETTERSETTER(::Matrix*, BoneMatrices, boneMatrices) + + ModelUnmanaged& operator=(const ::Model& model) { + set(model); + return *this; + } + + /** + * Loads a Model from the given file. + * + * @throws raylib::RaylibException Throws if failed to load the Model. + */ + void Load(const std::string& fileName) { + set(::LoadModel(fileName.c_str())); + if (!IsValid()) { + throw RaylibException("Failed to load Model from " + fileName); + } + } + + /** + * Loads a Model from the given Mesh. + * + * @throws raylib::RaylibException Throws if failed to load the Model. + */ + void Load(const ::Mesh& mesh) { + set(::LoadModelFromMesh(mesh)); + if (!IsValid()) { + throw RaylibException("Failed to load Model from Mesh"); + } + } + + /** + * Unload model (including meshes) from memory (RAM and/or VRAM). + */ + void Unload() { + if (meshes != nullptr || materials != nullptr) { + ::UnloadModel(*this); + meshes = nullptr; + materials = nullptr; + } + } + + /** + * Set material for a mesh. + */ + ModelUnmanaged& SetMeshMaterial(int meshId, int materialId) { + ::SetModelMeshMaterial(this, meshId, materialId); + return *this; + } + + /** + * Update model animation pose. + */ + ModelUnmanaged& UpdateAnimation(const ::ModelAnimation& anim, float frame) { + ::UpdateModelAnimation(*this, anim, frame); + return *this; + } + + /** + * Blend two model animation poses. + */ + ModelUnmanaged& BlendAnimation( + const ::ModelAnimation& animA, + float frameA, + const ::ModelAnimation& animB, + float frameB, + float blend) { + ::UpdateModelAnimationEx(*this, animA, frameA, animB, frameB, blend); + return *this; + } + + /** + * Check model animation skeleton match. + */ + [[nodiscard]] bool IsModelAnimationValid(const ::ModelAnimation& anim) const { + return ::IsModelAnimationValid(*this, anim); + } + + /** + * Draw a model (with texture if set). + */ + void Draw(::Vector3 position, float scale = 1.0f, ::Color tint = {255, 255, 255, 255}) const { + ::DrawModel(*this, position, scale, tint); + } + + /** + * Draw a model with extended parameters. + */ + void Draw( + ::Vector3 position, + ::Vector3 rotationAxis, + float rotationAngle = 0.0f, + ::Vector3 scale = {1.0f, 1.0f, 1.0f}, + ::Color tint = {255, 255, 255, 255}) const { + ::DrawModelEx(*this, position, rotationAxis, rotationAngle, scale, tint); + } + + /** + * Draw a model wires (with texture if set). + */ + void DrawWires(::Vector3 position, float scale = 1.0f, ::Color tint = {255, 255, 255, 255}) const { + ::DrawModelWires(*this, position, scale, tint); + } + + /** + * Draw a model wires (with texture if set) with extended parameters. + */ + void DrawWires( + ::Vector3 position, + ::Vector3 rotationAxis, + float rotationAngle = 0.0f, + ::Vector3 scale = {1.0f, 1.0f, 1.0f}, + ::Color tint = {255, 255, 255, 255}) const { + ::DrawModelWiresEx(*this, position, rotationAxis, rotationAngle, scale, tint); + } + + /** + * Compute model bounding box limits (considers all meshes). + */ + [[nodiscard]] BoundingBox GetBoundingBox() const { return ::GetModelBoundingBox(*this); } + + /** + * Compute model bounding box limits (considers all meshes). + */ + explicit operator BoundingBox() const { return ::GetModelBoundingBox(*this); } + + /** + * Determines whether or not the Model has data in it. + */ + [[nodiscard]] bool IsValid() const { return ::IsModelValid(*this); } + +protected: + void set(const ::Model& model) { + transform = model.transform; + + meshCount = model.meshCount; + materialCount = model.materialCount; + meshes = model.meshes; + materials = model.materials; + meshMaterial = model.meshMaterial; + + skeleton.boneCount = model.skeleton.boneCount; + skeleton.bones = model.skeleton.bones; + skeleton.bindPose = model.skeleton.bindPose; + currentPose = model.currentPose; + boneMatrices = model.boneMatrices; + } +}; +} // namespace raylib + +using RModelUnmanaged = raylib::ModelUnmanaged; + +#endif // RAYLIB_CPP_INCLUDE_MODELUNMANAGED_HPP_ diff --git a/include/Music.hpp b/include/Music.hpp index fc1307d5..c3f8dd6c 100644 --- a/include/Music.hpp +++ b/include/Music.hpp @@ -1,47 +1,25 @@ #ifndef RAYLIB_CPP_INCLUDE_MUSIC_HPP_ #define RAYLIB_CPP_INCLUDE_MUSIC_HPP_ -#include - -#include "./RaylibException.hpp" -#include "./raylib-cpp-utils.hpp" -#include "./raylib.hpp" +#include "./MusicUnmanaged.hpp" namespace raylib { /** - * Music stream type (audio file streaming from memory) + * Music stream type (audio file streaming from memory). + * + * The music stream will be unloaded on object destruction. Use raylib::MusicUnmanaged if you're looking to not unload. + * + * @see raylib::MusicUnmanaged */ -class Music : public ::Music { +class Music : public MusicUnmanaged { public: - Music( - ::AudioStream stream = {nullptr, nullptr, 0, 0, 0}, - unsigned int frameCount = 0, - bool looping = false, - int ctxType = 0, - void* ctxData = nullptr) - : ::Music{stream, frameCount, looping, ctxType, ctxData} {} - - Music(const ::Music& music) : ::Music(music) { } - - /** - * Load music stream from file - * - * @throws raylib::RaylibException Throws if the music failed to load. - */ - Music(const std::string& fileName) { Load(fileName); } - - /** - * Load music stream from memory - * - * @throws raylib::RaylibException Throws if the music failed to load. - */ - Music(const std::string& fileType, unsigned char* data, int dataSize) { Load(fileType, data, dataSize); } + using MusicUnmanaged::MusicUnmanaged; Music(const Music&) = delete; + Music& operator=(const Music&) = delete; Music(Music&& other) noexcept { set(other); - other.stream = {}; other.frameCount = 0; other.looping = false; @@ -49,170 +27,36 @@ class Music : public ::Music { other.ctxData = nullptr; } - /** - * Unload music stream - */ - ~Music() { Unload(); } - - GETTER(::AudioStream, Stream, stream) - GETTER(unsigned int, FrameCount, frameCount) - GETTERSETTER(bool, Looping, looping) - GETTER(int, CtxType, ctxType) - GETTER(void*, CtxData, ctxData) - - Music& operator=(const ::Music& music) { - set(music); - return *this; - } - - Music& operator=(const Music&) = delete; - Music& operator=(Music&& other) noexcept { if (this == &other) { return *this; } - Unload(); set(other); - other.ctxType = 0; other.ctxData = nullptr; other.looping = false; other.frameCount = 0; other.stream = {}; - - return *this; - } - - /** - * Unload music stream - */ - void Unload() { ::UnloadMusicStream(*this); } - - /** - * Start music playing - */ - Music& Play() { - ::PlayMusicStream(*this); - return *this; - } - - /** - * Updates buffers for music streaming - */ - Music& Update() { - ::UpdateMusicStream(*this); - return *this; - } - - /** - * Stop music playing - */ - Music& Stop() { - ::StopMusicStream(*this); - return *this; - } - - /** - * Pause music playing - */ - Music& Pause() { - ::PauseMusicStream(*this); - return *this; - } - - /** - * Resume music playing - */ - Music& Resume() { - ::ResumeMusicStream(*this); - return *this; - } - - /** - * Seek music to a position (in seconds) - */ - Music& Seek(float position) { - SeekMusicStream(*this, position); - return *this; - } - - /** - * Check if music is playing - */ - [[nodiscard]] bool IsPlaying() const { return ::IsMusicStreamPlaying(*this); } - - /** - * Set volume for music - */ - Music& SetVolume(float volume) { - ::SetMusicVolume(*this, volume); return *this; } - /** - * Set pitch for music - */ - Music& SetPitch(float pitch) { - ::SetMusicPitch(*this, pitch); - return *this; - } - - /** - * Set pan for a music (0.5 is center) - */ - Music& SetPan(float pan = 0.5f) { - ::SetMusicPan(*this, pan); + Music& operator=(const ::Music& music) { + Unload(); + set(music); return *this; } - /** - * Get music time length (in seconds) - */ - [[nodiscard]] float GetTimeLength() const { return ::GetMusicTimeLength(*this); } - - /** - * Get current music time played (in seconds) - */ - [[nodiscard]] float GetTimePlayed() const { return ::GetMusicTimePlayed(*this); } + ~Music() { Unload(); } - /** - * Load music stream from file - * - * @throws raylib::RaylibException Throws if the music failed to load. - */ void Load(const std::string& fileName) { - set(::LoadMusicStream(fileName.c_str())); - if (!IsValid()) { - throw RaylibException(TextFormat("Failed to load Music from file: %s", fileName.c_str())); - } + Unload(); + MusicUnmanaged::Load(fileName); } - /** - * Load music stream from memory - * - * @throws raylib::RaylibException Throws if the music failed to load. - */ void Load(const std::string& fileType, unsigned char* data, int dataSize) { - set(::LoadMusicStreamFromMemory(fileType.c_str(), data, dataSize)); - if (!IsValid()) { - throw RaylibException(TextFormat("Failed to load Music from %s file dat", fileType.c_str())); - } - } - - /** - * Retrieve whether or not the Music has been loaded. - * - * @return True or false depending on whether the Music has been loaded. - */ - bool IsValid() const { return ::IsMusicValid(*this); } -protected: - void set(const ::Music& music) { - stream = music.stream; - frameCount = music.frameCount; - looping = music.looping; - ctxType = music.ctxType; - ctxData = music.ctxData; + Unload(); + MusicUnmanaged::Load(fileType, data, dataSize); } }; } // namespace raylib diff --git a/include/MusicUnmanaged.hpp b/include/MusicUnmanaged.hpp new file mode 100644 index 00000000..4b8cee43 --- /dev/null +++ b/include/MusicUnmanaged.hpp @@ -0,0 +1,205 @@ +#ifndef RAYLIB_CPP_INCLUDE_MUSICUNMANAGED_HPP_ +#define RAYLIB_CPP_INCLUDE_MUSICUNMANAGED_HPP_ + +#include + +#include "./RaylibException.hpp" +#include "./raylib-cpp-utils.hpp" +#include "./raylib.hpp" + +namespace raylib { +/** + * A Music stream that is not managed by C++ RAII. + * + * Make sure to Unload() this if needed, otherwise use raylib::Music. + * + * @see raylib::Music + */ +class MusicUnmanaged : public ::Music { +public: + /** + * Creates a MusicUnmanaged with the given components. + */ + MusicUnmanaged( + ::AudioStream stream = {nullptr, nullptr, 0, 0, 0}, + unsigned int frameCount = 0, + bool looping = false, + int ctxType = 0, + void* ctxData = nullptr) + : ::Music{stream, frameCount, looping, ctxType, ctxData} {} + + /** + * Creates a MusicUnmanaged from an existing Music struct. + */ + MusicUnmanaged(const ::Music& music) : ::Music(music) {} + + /** + * Load music stream from file. + * + * @throws raylib::RaylibException Throws if the music failed to load. + */ + MusicUnmanaged(const std::string& fileName) { Load(fileName); } + + /** + * Load music stream from memory. + * + * @throws raylib::RaylibException Throws if the music failed to load. + */ + MusicUnmanaged(const std::string& fileType, unsigned char* data, int dataSize) { + Load(fileType, data, dataSize); + } + + GETTER(::AudioStream, Stream, stream) + GETTER(unsigned int, FrameCount, frameCount) + GETTERSETTER(bool, Looping, looping) + GETTER(int, CtxType, ctxType) + GETTER(void*, CtxData, ctxData) + + MusicUnmanaged& operator=(const ::Music& music) { + set(music); + return *this; + } + + /** + * Load music stream from file. + * + * @throws raylib::RaylibException Throws if the music failed to load. + */ + void Load(const std::string& fileName) { + set(::LoadMusicStream(fileName.c_str())); + if (!IsValid()) { + throw RaylibException(TextFormat("Failed to load Music from file: %s", fileName.c_str())); + } + } + + /** + * Load music stream from memory. + * + * @throws raylib::RaylibException Throws if the music failed to load. + */ + void Load(const std::string& fileType, unsigned char* data, int dataSize) { + set(::LoadMusicStreamFromMemory(fileType.c_str(), data, dataSize)); + if (!IsValid()) { + throw RaylibException(TextFormat("Failed to load Music from %s file data", fileType.c_str())); + } + } + + /** + * Unload music stream. + */ + void Unload() { + if (IsValid()) { + ::UnloadMusicStream(*this); + ctxData = nullptr; + ctxType = 0; + } + } + + /** + * Start music playing. + */ + MusicUnmanaged& Play() { + ::PlayMusicStream(*this); + return *this; + } + + /** + * Updates buffers for music streaming. + */ + MusicUnmanaged& Update() { + ::UpdateMusicStream(*this); + return *this; + } + + /** + * Stop music playing. + */ + MusicUnmanaged& Stop() { + ::StopMusicStream(*this); + return *this; + } + + /** + * Pause music playing. + */ + MusicUnmanaged& Pause() { + ::PauseMusicStream(*this); + return *this; + } + + /** + * Resume music playing. + */ + MusicUnmanaged& Resume() { + ::ResumeMusicStream(*this); + return *this; + } + + /** + * Seek music to a position (in seconds). + */ + MusicUnmanaged& Seek(float position) { + ::SeekMusicStream(*this, position); + return *this; + } + + /** + * Check if music is playing. + */ + [[nodiscard]] bool IsPlaying() const { return ::IsMusicStreamPlaying(*this); } + + /** + * Set volume for music. + */ + MusicUnmanaged& SetVolume(float volume) { + ::SetMusicVolume(*this, volume); + return *this; + } + + /** + * Set pitch for music. + */ + MusicUnmanaged& SetPitch(float pitch) { + ::SetMusicPitch(*this, pitch); + return *this; + } + + /** + * Set pan for a music (0.5 is center). + */ + MusicUnmanaged& SetPan(float pan = 0.5f) { + ::SetMusicPan(*this, pan); + return *this; + } + + /** + * Get music time length (in seconds). + */ + [[nodiscard]] float GetTimeLength() const { return ::GetMusicTimeLength(*this); } + + /** + * Get current music time played (in seconds). + */ + [[nodiscard]] float GetTimePlayed() const { return ::GetMusicTimePlayed(*this); } + + /** + * Retrieve whether or not the Music has been loaded. + * + * @return True or false depending on whether the Music has been loaded. + */ + [[nodiscard]] bool IsValid() const { return ::IsMusicValid(*this); } + +protected: + void set(const ::Music& music) { + stream = music.stream; + frameCount = music.frameCount; + looping = music.looping; + ctxType = music.ctxType; + ctxData = music.ctxData; + } +}; +} // namespace raylib + +using RMusicUnmanaged = raylib::MusicUnmanaged; + +#endif // RAYLIB_CPP_INCLUDE_MUSICUNMANAGED_HPP_ diff --git a/include/RenderTexture.hpp b/include/RenderTexture.hpp index fd973535..06ff3b30 100644 --- a/include/RenderTexture.hpp +++ b/include/RenderTexture.hpp @@ -1,120 +1,57 @@ #ifndef RAYLIB_CPP_INCLUDE_RENDERTEXTURE_HPP_ #define RAYLIB_CPP_INCLUDE_RENDERTEXTURE_HPP_ -#include "./TextureUnmanaged.hpp" -#include "./raylib-cpp-utils.hpp" +#include "./RenderTextureUnmanaged.hpp" namespace raylib { /** - * RenderTexture type, for texture rendering + * RenderTexture type, for texture rendering. + * + * The render texture will be unloaded on object destruction. Use raylib::RenderTextureUnmanaged + * if you're looking to not unload. + * + * @see raylib::RenderTextureUnmanaged */ -class RenderTexture : public ::RenderTexture { +class RenderTexture : public RenderTextureUnmanaged { public: - /** - * Default constructor to build an empty RenderTexture. - */ - RenderTexture() = default; - - RenderTexture(const ::RenderTexture& renderTexture) - : ::RenderTexture(renderTexture) { - // Nothing. - } - - RenderTexture(unsigned int id, const ::Texture& texture, const ::Texture& depth) - : ::RenderTexture{id, texture, depth} {} - - /** - * Load texture for rendering (framebuffer) - */ - RenderTexture(int width, int height) - : ::RenderTexture(::LoadRenderTexture(width, height)) { - // Nothing. - } + using RenderTextureUnmanaged::RenderTextureUnmanaged; RenderTexture(const RenderTexture&) = delete; + RenderTexture& operator=(const RenderTexture&) = delete; - RenderTexture(RenderTexture&& other) noexcept - { + RenderTexture(RenderTexture&& other) noexcept { set(other); - other.id = 0; other.texture = {}; other.depth = {}; } - GETTER(unsigned int, Id, id) - - /** - * Get the color buffer attachment texture. - */ - TextureUnmanaged GetTexture() { return texture; } - [[nodiscard]] TextureUnmanaged GetTexture() const { return texture; } - - void SetTexture(const ::Texture& newTexture) { texture = newTexture; } - - /** - * Depth buffer attachment texture - */ - TextureUnmanaged GetDepth() { return depth; } - - void SetDepth(const ::Texture& newDepth) { depth = newDepth; } - - RenderTexture& operator=(const ::RenderTexture& texture) { - set(texture); - return *this; - } - - RenderTexture& operator=(const RenderTexture&) = delete; - RenderTexture& operator=(RenderTexture&& other) noexcept { if (this == &other) { return *this; } - Unload(); set(other); - other.id = 0; other.texture = {}; other.depth = {}; - - return *this; - } - - ~RenderTexture() { Unload(); } - - void Unload() { UnloadRenderTexture(*this); } - - /** - * Initializes render texture for drawing - */ - RenderTexture& BeginMode() { - ::BeginTextureMode(*this); return *this; } - /** - * Ends drawing to render texture - */ - RenderTexture& EndMode() { - ::EndTextureMode(); + RenderTexture& operator=(const ::RenderTexture& other) { + Unload(); + set(other); return *this; } - /** - * Load texture for rendering (framebuffer) - */ - static RenderTexture Load(int width, int height) { return ::LoadRenderTexture(width, height); } + ~RenderTexture() { Unload(); } /** - * Retrieves whether or not the render texture is ready. + * Unload previous render texture, then load a new one. */ - [[nodiscard]] bool IsValid() const { return ::IsRenderTextureValid(*this); } -protected: - void set(const ::RenderTexture& renderTexture) { - id = renderTexture.id; - texture = renderTexture.texture; - depth = renderTexture.depth; + void Load(int width, int height) { + Unload(); + RenderTextureUnmanaged::Load(width, height); } }; diff --git a/include/RenderTextureUnmanaged.hpp b/include/RenderTextureUnmanaged.hpp new file mode 100644 index 00000000..7894564e --- /dev/null +++ b/include/RenderTextureUnmanaged.hpp @@ -0,0 +1,119 @@ +#ifndef RAYLIB_CPP_INCLUDE_RENDERTEXTUREUNMANAGED_HPP_ +#define RAYLIB_CPP_INCLUDE_RENDERTEXTUREUNMANAGED_HPP_ + +#include "./RaylibException.hpp" +#include "./TextureUnmanaged.hpp" +#include "./raylib-cpp-utils.hpp" + +namespace raylib { +/** + * A RenderTexture that is not managed by C++ RAII. + * + * Make sure to Unload() this if needed, otherwise use raylib::RenderTexture. + * + * @see raylib::RenderTexture + */ +class RenderTextureUnmanaged : public ::RenderTexture { +public: + /** + * Default constructor to build an empty RenderTexture. + */ + RenderTextureUnmanaged() : ::RenderTexture{0, {}, {}} {} + + /** + * Creates a RenderTexture from an existing RenderTexture struct. + */ + RenderTextureUnmanaged(const ::RenderTexture& renderTexture) : ::RenderTexture(renderTexture) {} + + /** + * Creates a RenderTexture from its components. + */ + RenderTextureUnmanaged(unsigned int id, const ::Texture& texture, const ::Texture& depth) + : ::RenderTexture{id, texture, depth} {} + + /** + * Load texture for rendering (framebuffer). + * + * @throws raylib::RaylibException Throws if failed to create the render texture. + */ + RenderTextureUnmanaged(int width, int height) { Load(width, height); } + + GETTER(unsigned int, Id, id) + + /** + * Get the color buffer attachment texture. + */ + TextureUnmanaged GetTexture() { return texture; } + [[nodiscard]] TextureUnmanaged GetTexture() const { return texture; } + void SetTexture(const ::Texture& newTexture) { texture = newTexture; } + + /** + * Get the depth buffer attachment texture. + */ + TextureUnmanaged GetDepth() { return depth; } + void SetDepth(const ::Texture& newDepth) { depth = newDepth; } + + RenderTextureUnmanaged& operator=(const ::RenderTexture& other) { + set(other); + return *this; + } + + /** + * Load texture for rendering (framebuffer). + * + * @throws raylib::RaylibException Throws if failed to create the render texture. + */ + void Load(int width, int height) { + set(::LoadRenderTexture(width, height)); + if (!IsValid()) { + throw RaylibException("Failed to create RenderTexture"); + } + } + + /** + * Unload render texture from GPU memory (VRAM). + */ + void Unload() { + if (IsValid()) { + ::UnloadRenderTexture(*this); + id = 0; + } + } + + /** + * Initializes render texture for drawing. + */ + RenderTextureUnmanaged& BeginMode() { + ::BeginTextureMode(*this); + return *this; + } + + /** + * Ends drawing to render texture. + */ + RenderTextureUnmanaged& EndMode() { + ::EndTextureMode(); + return *this; + } + + /** + * Retrieves whether or not the render texture is ready. + */ + [[nodiscard]] bool IsValid() const { return ::IsRenderTextureValid(*this); } + +protected: + void set(const ::RenderTexture& renderTexture) { + id = renderTexture.id; + texture = renderTexture.texture; + depth = renderTexture.depth; + } +}; + +using RenderTexture2DUnmanaged = RenderTextureUnmanaged; + +} // namespace raylib + +using RRenderTextureUnmanaged = raylib::RenderTextureUnmanaged; +using RRenderTexture2DUnmanaged = raylib::RenderTexture2DUnmanaged; + +#endif // RAYLIB_CPP_INCLUDE_RENDERTEXTUREUNMANAGED_HPP_ diff --git a/include/Shader.hpp b/include/Shader.hpp index 2c2c9fce..fb1b2de9 100644 --- a/include/Shader.hpp +++ b/include/Shader.hpp @@ -45,15 +45,6 @@ class Shader : public ShaderUnmanaged { * Unload shader from GPU memory (VRAM) */ ~Shader() { Unload(); } - - /** - * Unload shader from GPU memory (VRAM) - */ - void Unload() { - if (locs != nullptr) { - ::UnloadShader(*this); - } - } }; } // namespace raylib diff --git a/include/ShaderUnmanaged.hpp b/include/ShaderUnmanaged.hpp index e9a3344a..d32fb2da 100644 --- a/include/ShaderUnmanaged.hpp +++ b/include/ShaderUnmanaged.hpp @@ -1,5 +1,5 @@ -#ifndef RAYLIB_CPP_INCLUDE_UNMANAGEDSHADER_HPP_ -#define RAYLIB_CPP_INCLUDE_UNMANAGEDSHADER_HPP_ +#ifndef RAYLIB_CPP_INCLUDE_SHADERUNMANAGED_HPP_ +#define RAYLIB_CPP_INCLUDE_SHADERUNMANAGED_HPP_ #include "./raylib-cpp-utils.hpp" #include "./raylib.hpp" @@ -129,6 +129,16 @@ class ShaderUnmanaged : public ::Shader { return *this; } + /** + * Unload shader from GPU memory (VRAM). + */ + void Unload() { + if (locs != nullptr) { + ::UnloadShader(*this); + locs = nullptr; + } + } + /** * Retrieves whether or not the shader is ready. */ @@ -143,4 +153,4 @@ class ShaderUnmanaged : public ::Shader { using RShaderUnmanaged = raylib::ShaderUnmanaged; -#endif // RAYLIB_CPP_INCLUDE_UNMANAGEDSHADER_HPP_ +#endif // RAYLIB_CPP_INCLUDE_SHADERUNMANAGED_HPP_ diff --git a/include/Sound.hpp b/include/Sound.hpp index e1cce60a..e6c29168 100644 --- a/include/Sound.hpp +++ b/include/Sound.hpp @@ -1,196 +1,55 @@ #ifndef RAYLIB_CPP_INCLUDE_SOUND_HPP_ #define RAYLIB_CPP_INCLUDE_SOUND_HPP_ -#include - -#include "./RaylibException.hpp" -#include "./raylib-cpp-utils.hpp" -#include "./raylib.hpp" +#include "./SoundUnmanaged.hpp" namespace raylib { /** - * Wave/Sound management functions + * Wave/Sound management functions. + * + * The sound will be unloaded on object destruction. Use raylib::SoundUnmanaged if you're looking to not unload. * * @code * raylib::Sound boom("boom.wav"); * boom.Play(); * @endcode + * + * @see raylib::SoundUnmanaged */ -class Sound : public ::Sound { +class Sound : public SoundUnmanaged { public: + using SoundUnmanaged::SoundUnmanaged; + Sound(const Sound&) = delete; Sound& operator=(const Sound&) = delete; - Sound() { - stream = {nullptr, nullptr, 0, 0, 0}; - frameCount = 0; - } - - Sound(::AudioStream stream, unsigned int frameCount) : ::Sound{stream, frameCount} { - // Nothing. - } - Sound(Sound&& other) noexcept { set(other); - other.stream = {nullptr, nullptr, 0, 0, 0}; other.frameCount = 0; } - /** - * Loads a sound from the given file. - * - * @throws raylib::RaylibException Throws if the Sound failed to load. - */ - Sound(const std::string& fileName) { Load(fileName); } - - /** - * Loads a sound from the given Wave. - * - * @throws raylib::RaylibException Throws if the Sound failed to load. - */ - Sound(const ::Wave& wave) { Load(wave); } - - ~Sound() { Unload(); } - - GETTER(unsigned int, FrameCount, frameCount) - GETTER(::AudioStream, Stream, stream) - Sound& operator=(Sound&& other) noexcept { if (this == &other) { return *this; } - Unload(); set(other); other.frameCount = 0; other.stream = {nullptr, nullptr, 0, 0, 0}; - return *this; } - /** - * Update sound buffer with new data - */ - Sound& Update(const void* data, int samplesCount) { - ::UpdateSound(*this, data, samplesCount); - return *this; - } - - /** - * Update sound buffer with new data, assuming it's the same sample count. - */ - Sound& Update(const void* data) { - ::UpdateSound(*this, data, static_cast(frameCount)); - return *this; - } - - /** - * Unload sound - */ - void Unload() { - // Protect against calling UnloadSound() twice. - if (frameCount != 0) { - ::UnloadSound(*this); - frameCount = 0; - } - } - - /** - * Play a sound - */ - Sound& Play() { - ::PlaySound(*this); - return *this; - } - - /** - * Stop playing a sound - */ - Sound& Stop() { - ::StopSound(*this); - return *this; - } - - /** - * Pause a sound - */ - Sound& Pause() { - ::PauseSound(*this); - return *this; - } - - /** - * Resume a paused sound - */ - Sound& Resume() { - ::ResumeSound(*this); - return *this; - } - - /** - * Check if a sound is currently playing - */ - [[nodiscard]] bool IsPlaying() const { return ::IsSoundPlaying(*this); } - - /** - * Set volume for a sound (1.0 is max level) - */ - Sound& SetVolume(float volume) { - ::SetSoundVolume(*this, volume); - return *this; - } - - /** - * Set pitch for a sound (1.0 is base level) - */ - Sound& SetPitch(float pitch) { - ::SetSoundPitch(*this, pitch); - return *this; - } - - /** - * Set pan for a sound (0.5 is center) - */ - Sound& SetPan(float pan = 0.5f) { - ::SetSoundPan(*this, pan); - return *this; - } + ~Sound() { Unload(); } - /** - * Load a sound from the given file. - * - * @throws raylib::RaylibException Throws if the Sound failed to load. - */ void Load(const std::string& fileName) { - set(::LoadSound(fileName.c_str())); - if (!IsValid()) { - throw RaylibException("Failed to load Sound from file"); - } + Unload(); + SoundUnmanaged::Load(fileName); } - /** - * Loads the given Wave object into the Sound. - * - * @throws raylib::RaylibException Throws if the Sound failed to load. - */ void Load(const ::Wave& wave) { - set(::LoadSoundFromWave(wave)); - if (!IsValid()) { - throw RaylibException("Failed to load Wave"); - } - } - - /** - * Retrieve whether or not the Sound buffer is loaded. - * - * @return True or false depending on whether the Sound buffer is loaded. - */ - [[nodiscard]] bool IsValid() const { return ::IsSoundValid(*this); } -protected: - void set(const ::Sound& sound) { - frameCount = sound.frameCount; - stream = sound.stream; + Unload(); + SoundUnmanaged::Load(wave); } }; } // namespace raylib diff --git a/include/SoundUnmanaged.hpp b/include/SoundUnmanaged.hpp new file mode 100644 index 00000000..3ea632dc --- /dev/null +++ b/include/SoundUnmanaged.hpp @@ -0,0 +1,186 @@ +#ifndef RAYLIB_CPP_INCLUDE_SOUNDUNMANAGED_HPP_ +#define RAYLIB_CPP_INCLUDE_SOUNDUNMANAGED_HPP_ + +#include + +#include "./RaylibException.hpp" +#include "./raylib-cpp-utils.hpp" +#include "./raylib.hpp" + +namespace raylib { +/** + * A Sound that is not managed by C++ RAII. + * + * Make sure to Unload() this if needed, otherwise use raylib::Sound. + * + * @see raylib::Sound + */ +class SoundUnmanaged : public ::Sound { +public: + /** + * Default constructor, creates an empty Sound. + */ + SoundUnmanaged() : ::Sound{{nullptr, nullptr, 0, 0, 0}, 0} {} + + /** + * Creates a SoundUnmanaged from its components. + */ + SoundUnmanaged(::AudioStream stream, unsigned int frameCount) : ::Sound{stream, frameCount} {} + + /** + * Creates a SoundUnmanaged from an existing Sound struct. + */ + SoundUnmanaged(const ::Sound& sound) : ::Sound(sound) {} + + /** + * Loads a Sound from the given file. + * + * @throws raylib::RaylibException Throws if the Sound failed to load. + */ + SoundUnmanaged(const std::string& fileName) { Load(fileName); } + + /** + * Loads a Sound from the given Wave. + * + * @throws raylib::RaylibException Throws if the Sound failed to load. + */ + SoundUnmanaged(const ::Wave& wave) { Load(wave); } + + GETTER(unsigned int, FrameCount, frameCount) + GETTER(::AudioStream, Stream, stream) + + SoundUnmanaged& operator=(const ::Sound& sound) { + set(sound); + return *this; + } + + /** + * Load a sound from the given file. + * + * @throws raylib::RaylibException Throws if the Sound failed to load. + */ + void Load(const std::string& fileName) { + set(::LoadSound(fileName.c_str())); + if (!IsValid()) { + throw RaylibException("Failed to load Sound from file"); + } + } + + /** + * Load a sound from the given Wave. + * + * @throws raylib::RaylibException Throws if the Sound failed to load. + */ + void Load(const ::Wave& wave) { + set(::LoadSoundFromWave(wave)); + if (!IsValid()) { + throw RaylibException("Failed to load Wave"); + } + } + + /** + * Unload sound. + */ + void Unload() { + // Protect against calling UnloadSound() twice. + if (frameCount != 0) { + ::UnloadSound(*this); + frameCount = 0; + } + } + + /** + * Update sound buffer with new data. + */ + SoundUnmanaged& Update(const void* data, int samplesCount) { + ::UpdateSound(*this, data, samplesCount); + return *this; + } + + /** + * Update sound buffer with new data, assuming it's the same sample count. + */ + SoundUnmanaged& Update(const void* data) { + ::UpdateSound(*this, data, static_cast(frameCount)); + return *this; + } + + /** + * Play a sound. + */ + SoundUnmanaged& Play() { + ::PlaySound(*this); + return *this; + } + + /** + * Stop playing a sound. + */ + SoundUnmanaged& Stop() { + ::StopSound(*this); + return *this; + } + + /** + * Pause a sound. + */ + SoundUnmanaged& Pause() { + ::PauseSound(*this); + return *this; + } + + /** + * Resume a paused sound. + */ + SoundUnmanaged& Resume() { + ::ResumeSound(*this); + return *this; + } + + /** + * Check if a sound is currently playing. + */ + [[nodiscard]] bool IsPlaying() const { return ::IsSoundPlaying(*this); } + + /** + * Set volume for a sound (1.0 is max level). + */ + SoundUnmanaged& SetVolume(float volume) { + ::SetSoundVolume(*this, volume); + return *this; + } + + /** + * Set pitch for a sound (1.0 is base level). + */ + SoundUnmanaged& SetPitch(float pitch) { + ::SetSoundPitch(*this, pitch); + return *this; + } + + /** + * Set pan for a sound (0.5 is center). + */ + SoundUnmanaged& SetPan(float pan = 0.5f) { + ::SetSoundPan(*this, pan); + return *this; + } + + /** + * Retrieve whether or not the Sound buffer is loaded. + * + * @return True or false depending on whether the Sound buffer is loaded. + */ + [[nodiscard]] bool IsValid() const { return ::IsSoundValid(*this); } + +protected: + void set(const ::Sound& sound) { + stream = sound.stream; + frameCount = sound.frameCount; + } +}; +} // namespace raylib + +using RSoundUnmanaged = raylib::SoundUnmanaged; + +#endif // RAYLIB_CPP_INCLUDE_SOUNDUNMANAGED_HPP_ diff --git a/include/VrStereoConfig.hpp b/include/VrStereoConfig.hpp index 0b767faa..371126f1 100644 --- a/include/VrStereoConfig.hpp +++ b/include/VrStereoConfig.hpp @@ -12,6 +12,11 @@ class VrStereoConfig : public ::VrStereoConfig { public: VrStereoConfig(const ::VrDeviceInfo& info) { Load(info); } + VrStereoConfig(const VrStereoConfig&) = delete; + VrStereoConfig& operator=(const VrStereoConfig&) = delete; + VrStereoConfig(VrStereoConfig&&) = default; + VrStereoConfig& operator=(VrStereoConfig&&) = default; + /** * Load VR stereo config for VR simulator device parameters */ diff --git a/include/Wave.hpp b/include/Wave.hpp index d012376c..736db90d 100644 --- a/include/Wave.hpp +++ b/include/Wave.hpp @@ -1,51 +1,25 @@ #ifndef RAYLIB_CPP_INCLUDE_WAVE_HPP_ #define RAYLIB_CPP_INCLUDE_WAVE_HPP_ -#include - -#include "./RaylibException.hpp" -#include "./raylib-cpp-utils.hpp" -#include "./raylib.hpp" +#include "./WaveUnmanaged.hpp" namespace raylib { /** - * Wave type, defines audio wave data + * Wave type, defines audio wave data. + * + * The wave will be unloaded on object destruction. Use raylib::WaveUnmanaged if you're looking to not unload. + * Unlike other resource types, Wave supports value-copy semantics via WaveCopy(). + * + * @see raylib::WaveUnmanaged */ -class Wave : public ::Wave { +class Wave : public WaveUnmanaged { public: - Wave(const ::Wave& wave) : ::Wave(wave) { } - - Wave( - unsigned int frameCount = 0, - unsigned int sampleRate = 0, - unsigned int sampleSize = 0, - unsigned int channels = 0, - void* data = nullptr) - : ::Wave{frameCount, sampleRate, sampleSize, channels, data} { - // Nothing. - } - - /** - * Load wave data from file - * - * @throws raylib::RaylibException Throws if the Wave failed to load. - */ - Wave(const std::string& fileName) { Load(fileName); } - - /** - * Load wave from memory buffer, fileType refers to extension: i.e. "wav" - * - * @throws raylib::RaylibException Throws if the Wave failed to load. - */ - Wave(const std::string& fileType, const unsigned char* fileData, int dataSize) { - Load(fileType, fileData, dataSize); - } + using WaveUnmanaged::WaveUnmanaged; Wave(const Wave& other) { set(other.Copy()); } Wave(Wave&& other) noexcept { set(other); - other.frameCount = 0; other.sampleRate = 0; other.sampleSize = 0; @@ -53,18 +27,8 @@ class Wave : public ::Wave { other.data = nullptr; } - /** - * Unload wave data - */ - ~Wave() { Unload(); } - - GETTER(unsigned int, FrameCount, frameCount) - GETTER(unsigned int, SampleRate, sampleRate) - GETTER(unsigned int, SampleSize, sampleSize) - GETTER(unsigned int, Channels, channels) - GETTER(void*, Data, data) - Wave& operator=(const ::Wave& wave) { + Unload(); set(wave); return *this; } @@ -73,10 +37,8 @@ class Wave : public ::Wave { if (this == &other) { return *this; } - Unload(); set(other.Copy()); - return *this; } @@ -84,127 +46,28 @@ class Wave : public ::Wave { if (this == &other) { return *this; } - Unload(); set(other); - other.frameCount = 0; other.sampleRate = 0; other.sampleSize = 0; other.channels = 0; other.data = nullptr; - return *this; } - /** - * Copy a wave to a new wave - */ - [[nodiscard]] ::Wave Copy() const { return ::WaveCopy(*this); } - - /** - * Crop a wave to defined samples range - */ - Wave& Crop(int initSample, int finalSample) { - ::WaveCrop(this, initSample, finalSample); - return *this; - } - - /** - * Convert wave data to desired format - */ - Wave& Format(int SampleRate, int SampleSize, int Channels = 2) { - ::WaveFormat(this, SampleRate, SampleSize, Channels); - return *this; - } - - /** - * Load samples data from wave as a floats array - */ - float* LoadSamples() { return ::LoadWaveSamples(*this); } - - /** - * Unload samples data loaded with LoadWaveSamples() - */ - static void UnloadSamples(float* samples) { ::UnloadWaveSamples(samples); } - - /** - * Export wave data to file, returns true on success - */ - bool Export(const std::string& fileName) { - // TODO(RobLoach): Throw exception on error. - return ::ExportWave(*this, fileName.c_str()); - } - - /** - * Export wave sample data to code (.h), returns true on success - */ - bool ExportAsCode(const std::string& fileName) { - // TODO(RobLoach): Throw exception on error. - return ::ExportWaveAsCode(*this, fileName.c_str()); - } - - /** - * Unload wave data - */ - void Unload() { - // Protect against calling UnloadWave() twice. - if (data != nullptr) { - ::UnloadWave(*this); - data = nullptr; - } - } - - /** - * Load sound from wave data - */ - ::Sound LoadSound() { return ::LoadSoundFromWave(*this); } - - /** - * Load sound from wave data - */ - operator ::Sound() { return LoadSound(); } + ~Wave() { Unload(); } - /** - * Load wave data from file. - * - * @throws raylib::RaylibException Throws if the Wave failed to load. - */ void Load(const std::string& fileName) { - set(::LoadWave(fileName.c_str())); - if (!IsValid()) { - throw RaylibException("Failed to load Wave from file: " + fileName); - } + Unload(); + WaveUnmanaged::Load(fileName); } - /** - * Load wave from memory buffer, fileType refers to extension: i.e. "wav" - * - * @throws raylib::RaylibException Throws if the Wave failed to load. - */ void Load(const std::string& fileType, const unsigned char* fileData, int dataSize) { - set(::LoadWaveFromMemory(fileType.c_str(), fileData, dataSize)); - if (!IsValid()) { - throw RaylibException("Failed to load Wave from file data of type: " + fileType); - } - } - - /** - * Retrieve whether or not the Wave data has been loaded. - * - * @return True or false depending on whether the wave data has been loaded. - */ - [[nodiscard]] bool IsValid() const { return ::IsWaveValid(*this); } -protected: - void set(const ::Wave& wave) { - frameCount = wave.frameCount; - sampleRate = wave.sampleRate; - sampleSize = wave.sampleSize; - channels = wave.channels; - data = wave.data; + Unload(); + WaveUnmanaged::Load(fileType, fileData, dataSize); } }; - } // namespace raylib using RWave = raylib::Wave; diff --git a/include/WaveUnmanaged.hpp b/include/WaveUnmanaged.hpp new file mode 100644 index 00000000..711294a0 --- /dev/null +++ b/include/WaveUnmanaged.hpp @@ -0,0 +1,169 @@ +#ifndef RAYLIB_CPP_INCLUDE_WAVEUNMANAGED_HPP_ +#define RAYLIB_CPP_INCLUDE_WAVEUNMANAGED_HPP_ + +#include + +#include "./RaylibException.hpp" +#include "./raylib-cpp-utils.hpp" +#include "./raylib.hpp" + +namespace raylib { +/** + * A Wave that is not managed by C++ RAII. + * + * Make sure to Unload() this if needed, otherwise use raylib::Wave. + * + * @see raylib::Wave + */ +class WaveUnmanaged : public ::Wave { +public: + /** + * Creates a WaveUnmanaged from an existing Wave struct. + */ + WaveUnmanaged(const ::Wave& wave) : ::Wave(wave) {} + + /** + * Creates a WaveUnmanaged from its components. + */ + WaveUnmanaged( + unsigned int frameCount = 0, + unsigned int sampleRate = 0, + unsigned int sampleSize = 0, + unsigned int channels = 0, + void* data = nullptr) + : ::Wave{frameCount, sampleRate, sampleSize, channels, data} {} + + /** + * Load wave data from file. + * + * @throws raylib::RaylibException Throws if the Wave failed to load. + */ + WaveUnmanaged(const std::string& fileName) { Load(fileName); } + + /** + * Load wave from memory buffer; fileType refers to extension: i.e. "wav". + * + * @throws raylib::RaylibException Throws if the Wave failed to load. + */ + WaveUnmanaged(const std::string& fileType, const unsigned char* fileData, int dataSize) { + Load(fileType, fileData, dataSize); + } + + GETTER(unsigned int, FrameCount, frameCount) + GETTER(unsigned int, SampleRate, sampleRate) + GETTER(unsigned int, SampleSize, sampleSize) + GETTER(unsigned int, Channels, channels) + GETTER(void*, Data, data) + + WaveUnmanaged& operator=(const ::Wave& wave) { + set(wave); + return *this; + } + + /** + * Load wave data from file. + * + * @throws raylib::RaylibException Throws if the Wave failed to load. + */ + void Load(const std::string& fileName) { + set(::LoadWave(fileName.c_str())); + if (!IsValid()) { + throw RaylibException("Failed to load Wave from file: " + fileName); + } + } + + /** + * Load wave from memory buffer; fileType refers to extension: i.e. "wav". + * + * @throws raylib::RaylibException Throws if the Wave failed to load. + */ + void Load(const std::string& fileType, const unsigned char* fileData, int dataSize) { + set(::LoadWaveFromMemory(fileType.c_str(), fileData, dataSize)); + if (!IsValid()) { + throw RaylibException("Failed to load Wave from file data of type: " + fileType); + } + } + + /** + * Unload wave data. + */ + void Unload() { + // Protect against calling UnloadWave() twice. + if (data != nullptr) { + ::UnloadWave(*this); + data = nullptr; + } + } + + /** + * Copy a wave to a new wave. + */ + [[nodiscard]] ::Wave Copy() const { return ::WaveCopy(*this); } + + /** + * Crop a wave to defined samples range. + */ + WaveUnmanaged& Crop(int initSample, int finalSample) { + ::WaveCrop(this, initSample, finalSample); + return *this; + } + + /** + * Convert wave data to desired format. + */ + WaveUnmanaged& Format(int sampleRate, int sampleSize, int channels = 2) { + ::WaveFormat(this, sampleRate, sampleSize, channels); + return *this; + } + + /** + * Load samples data from wave as a floats array. + */ + float* LoadSamples() { return ::LoadWaveSamples(*this); } + + /** + * Unload samples data loaded with LoadWaveSamples(). + */ + static void UnloadSamples(float* samples) { ::UnloadWaveSamples(samples); } + + /** + * Export wave data to file, returns true on success. + */ + bool Export(const std::string& fileName) { return ::ExportWave(*this, fileName.c_str()); } + + /** + * Export wave sample data to code (.h), returns true on success. + */ + bool ExportAsCode(const std::string& fileName) { return ::ExportWaveAsCode(*this, fileName.c_str()); } + + /** + * Load sound from wave data. + */ + ::Sound LoadSound() { return ::LoadSoundFromWave(*this); } + + /** + * Load sound from wave data. + */ + operator ::Sound() { return LoadSound(); } + + /** + * Retrieve whether or not the Wave data has been loaded. + * + * @return True or false depending on whether the wave data has been loaded. + */ + [[nodiscard]] bool IsValid() const { return ::IsWaveValid(*this); } + +protected: + void set(const ::Wave& wave) { + frameCount = wave.frameCount; + sampleRate = wave.sampleRate; + sampleSize = wave.sampleSize; + channels = wave.channels; + data = wave.data; + } +}; +} // namespace raylib + +using RWaveUnmanaged = raylib::WaveUnmanaged; + +#endif // RAYLIB_CPP_INCLUDE_WAVEUNMANAGED_HPP_ diff --git a/include/Window.hpp b/include/Window.hpp index 20c5138d..845e12b2 100644 --- a/include/Window.hpp +++ b/include/Window.hpp @@ -38,6 +38,9 @@ class Window { Init(width, height, title, flags, logLevel); } + Window(const Window&) = delete; + Window& operator=(const Window&) = delete; + /** * Close window and unload OpenGL context */ diff --git a/include/raylib-cpp.hpp b/include/raylib-cpp.hpp index 1ac27bab..3c4ffa02 100644 --- a/include/raylib-cpp.hpp +++ b/include/raylib-cpp.hpp @@ -33,6 +33,7 @@ #include "./AudioDevice.hpp" #include "./AudioStream.hpp" +#include "./AudioStreamUnmanaged.hpp" #include "./AutomationEventList.hpp" #include "./BoundingBox.hpp" #include "./Camera2D.hpp" @@ -41,24 +42,30 @@ #include "./FileData.hpp" #include "./FileText.hpp" #include "./Font.hpp" +#include "./FontUnmanaged.hpp" #include "./Functions.hpp" #include "./Gamepad.hpp" #include "./Image.hpp" #include "./Keyboard.hpp" #include "./Material.hpp" +#include "./MaterialUnmanaged.hpp" #include "./Matrix.hpp" #include "./Mesh.hpp" #include "./Model.hpp" +#include "./ModelUnmanaged.hpp" #include "./ModelAnimation.hpp" #include "./Mouse.hpp" #include "./Music.hpp" +#include "./MusicUnmanaged.hpp" #include "./Ray.hpp" #include "./RayCollision.hpp" #include "./RaylibException.hpp" #include "./Rectangle.hpp" #include "./RenderTexture.hpp" +#include "./RenderTextureUnmanaged.hpp" #include "./Shader.hpp" #include "./Sound.hpp" +#include "./SoundUnmanaged.hpp" #include "./Text.hpp" #include "./Texture.hpp" #include "./TextureUnmanaged.hpp" @@ -68,6 +75,7 @@ #include "./Vector4.hpp" #include "./VrStereoConfig.hpp" #include "./Wave.hpp" +#include "./WaveUnmanaged.hpp" #include "./Window.hpp" /**