diff --git a/.github/workflows/linux.yml b/.github/workflows/linux.yml index 2ce54e09..6be4cea5 100644 --- a/.github/workflows/linux.yml +++ b/.github/workflows/linux.yml @@ -36,7 +36,7 @@ jobs: - name: Install deps run: | sudo apt-get update - sudo apt-get install libpthread-stubs0-dev libgl1-mesa-dev libx11-dev libx11-xcb-dev libxcb-image0-dev libxrandr-dev libxcb-randr0-dev libudev-dev libfreetype6-dev libglew-dev libjpeg8-dev libgpgme11-dev libsndfile1-dev libopenal-dev libjpeg62 libxcursor-dev cmake libclang-dev clang libflac-dev + sudo apt-get install libpthread-stubs0-dev libgl1-mesa-dev libx11-dev libx11-xcb-dev libxcb-image0-dev libxrandr-dev libxcb-randr0-dev libudev-dev libfreetype6-dev libglew-dev libjpeg8-dev libgpgme11-dev libsndfile1-dev libopenal-dev libjpeg62 libxcursor-dev cmake libclang-dev clang libflac-dev libxi-dev - name: Build run: | git submodule update --init diff --git a/.github/workflows/windows.yml b/.github/workflows/windows.yml index fa79a87a..5af8277f 100644 --- a/.github/workflows/windows.yml +++ b/.github/workflows/windows.yml @@ -36,8 +36,7 @@ jobs: - uses: actions/checkout@v4 - name: Build run: | - git submodule update --init - cp .\SFML\extlibs\bin\x64\openal32.dll . + git submodule update --init --recursive cargo build --verbose - name: Run tests run: | diff --git a/CSFML/src/Audio/CustomSoundRecorder.cpp b/CSFML/src/Audio/CustomSoundRecorder.cpp index a3f69417..e19dfc12 100644 --- a/CSFML/src/Audio/CustomSoundRecorder.cpp +++ b/CSFML/src/Audio/CustomSoundRecorder.cpp @@ -18,16 +18,13 @@ class sfCustomSoundRecorder final : public sf::SoundRecorder { myStopCb(onStop), myUserData(userData) { } - virtual void setProcessingInterval(int64_t interval) final { - sf::SoundRecorder::setProcessingInterval(sf::microseconds(interval)); - } private: virtual bool onStart() final { return myStartCb(myUserData); } - virtual bool onProcessSamples(const sf::Int16 *samples, std::size_t sampleCount) final { + virtual bool onProcessSamples(const std::int16_t *samples, std::size_t sampleCount) final { return myProcessCb(samples, sampleCount, myUserData); } @@ -64,10 +61,6 @@ extern "C" unsigned int sfCustomSoundRecorder_getSampleRate(const sfCustomSoundR return soundRecorder->getSampleRate(); } -extern "C" void sfCustomSoundRecorder_setProcessingInterval(sfCustomSoundRecorder *soundRecorder, int64_t interval) { - soundRecorder->setProcessingInterval(interval); -} - extern "C" bool sfCustomSoundRecorder_setDevice(sfCustomSoundRecorder *soundRecorder, const char *name) { return soundRecorder->setDevice(name); } diff --git a/CSFML/src/Audio/CustomSoundStream.cpp b/CSFML/src/Audio/CustomSoundStream.cpp index 80ab04fe..d8fb8988 100644 --- a/CSFML/src/Audio/CustomSoundStream.cpp +++ b/CSFML/src/Audio/CustomSoundStream.cpp @@ -1,6 +1,13 @@ +#include "Audio/EffectProcessor.hpp" +#include "Audio/SoundSourceCone.hpp" +#include "Audio/SoundStatus.hpp" +#include "Audio/SoundChannel.hpp" +#include "SFML/Audio/SoundChannel.hpp" #include "System/Vector3.hpp" #include -#include +#include +#include +#include typedef bool (*sfCustomSoundStreamGetDataCb)(sf::SoundStream::Chunk *, void *); typedef void (*sfCustomSoundStreamSeekCb)(int64_t, void *); @@ -11,10 +18,16 @@ class sfCustomSoundStream final : public sf::SoundStream { sfCustomSoundStreamSeekCb onSeek, unsigned int channelCount, unsigned int sampleRate, + const sfSoundChannel *soundChannels, + size_t soundChannelMapLen, void *userData) : myGetDataCb(onGetData), mySeekCallCb(onSeek), myUserData(userData) { - initialize(channelCount, sampleRate); + std::vector castedSoundChannels(soundChannelMapLen); + for (size_t i = 0; i < soundChannelMapLen; i++) { + castedSoundChannels.push_back(static_cast(soundChannels[i])); + } + initialize(channelCount, sampleRate, castedSoundChannels); } private: @@ -35,12 +48,10 @@ extern "C" sfCustomSoundStream *sfCustomSoundStream_new(sfCustomSoundStreamGetDa sfCustomSoundStreamSeekCb onSeek, unsigned int channelCount, unsigned int sampleRate, + const sfSoundChannel *channelMap, + size_t soundChannelMapLen, void *userData) { - return new sfCustomSoundStream(onGetData, onSeek, channelCount, sampleRate, userData); -} - -extern "C" void sfCustomSoundStream_del(sfCustomSoundStream *soundStream) { - delete soundStream; + return new sfCustomSoundStream(onGetData, onSeek, channelCount, sampleRate, channelMap, soundChannelMapLen, userData); } extern "C" void sfCustomSoundStream_play(sfCustomSoundStream *soundStream) { @@ -55,9 +66,8 @@ extern "C" void sfCustomSoundStream_stop(sfCustomSoundStream *soundStream) { soundStream->stop(); } -extern "C" sf::SoundStream::Status sfCustomSoundStream_getStatus(const sfCustomSoundStream *soundStream) { - - return soundStream->getStatus(); +extern "C" sfSoundStatus sfCustomSoundStream_getStatus(const sfCustomSoundStream *soundStream) { + return static_cast(soundStream->getStatus()); } extern "C" unsigned int sfCustomSoundStream_getChannelCount(const sfCustomSoundStream *soundStream) { @@ -68,16 +78,48 @@ extern "C" unsigned int sfCustomSoundStream_getSampleRate(const sfCustomSoundStr return soundStream->getSampleRate(); } +extern "C" const std::vector *sfCustomSoundStream_getChannelMap(const sfCustomSoundStream *soundStream) { + return new std::vector(soundStream->getChannelMap()); +} + extern "C" void sfCustomSoundStream_setPitch(sfCustomSoundStream *soundStream, float pitch) { soundStream->setPitch(pitch); } +extern "C" void sfCustomSoundStream_setPan(sfCustomSoundStream *soundStream, float pan) { + soundStream->setPan(pan); +} + extern "C" void sfCustomSoundStream_setVolume(sfCustomSoundStream *soundStream, float volume) { soundStream->setVolume(volume); } -extern "C" void sfCustomSoundStream_setPosition(sfCustomSoundStream *soundStream, sfVector3f position) { - soundStream->setPosition(position.x, position.y, position.z); +extern "C" void sfCustomSoundStream_setSpatializationEnabled(sfCustomSoundStream *soundStream, bool enabled) { + soundStream->setSpatializationEnabled(enabled); +} + +extern "C" void sfCustomSoundStream_setPosition(sfCustomSoundStream *soundStream, sf::Vector3f position) { + soundStream->setPosition(position); +} + +extern "C" void sfCustomSoundStream_setDirection(sfCustomSoundStream *soundStream, sfVector3f position) { + soundStream->setDirection(convertVector3(position)); +} + +extern "C" void sfCustomSoundStream_setCone(sfCustomSoundStream *soundStream, sfSoundSourceCone cone) { + soundStream->setCone(convertCone(cone)); +} + +extern "C" void sfCustomSoundStream_setVelocity(sfCustomSoundStream *soundStream, sfVector3f velocity) { + soundStream->setVelocity(convertVector3(velocity)); +} + +extern "C" void sfCustomSoundStream_setDopplerFactor(sfCustomSoundStream *soundStream, float factor) { + soundStream->setDopplerFactor(factor); +} + +extern "C" void sfCustomSoundStream_setDirectionalAttenuationFactor(sfCustomSoundStream *soundStream, float factor) { + soundStream->setDirectionalAttenuationFactor(factor); } extern "C" void sfCustomSoundStream_setRelativeToListener(sfCustomSoundStream *soundStream, bool relative) { @@ -88,6 +130,18 @@ extern "C" void sfCustomSoundStream_setMinDistance(sfCustomSoundStream *soundStr soundStream->setMinDistance(distance); } +extern "C" void sfCustomSoundStream_setMaxDistance(sfCustomSoundStream *soundStream, float distance) { + soundStream->setMaxDistance(distance); +} + +extern "C" void sfCustomSoundStream_setMinGain(sfCustomSoundStream *soundStream, float gain) { + soundStream->setMinGain(gain); +} + +extern "C" void sfCustomSoundStream_setMaxGain(sfCustomSoundStream *soundStream, float gain) { + soundStream->setMaxGain(gain); +} + extern "C" void sfCustomSoundStream_setAttenuation(sfCustomSoundStream *soundStream, float attenuation) { soundStream->setAttenuation(attenuation); } @@ -96,21 +150,48 @@ extern "C" void sfCustomSoundStream_setPlayingOffset(sfCustomSoundStream *soundS soundStream->setPlayingOffset(sf::microseconds(timeOffset)); } -extern "C" void sfCustomSoundStream_setLoop(sfCustomSoundStream *soundStream, bool loop) { - soundStream->setLoop(loop); +extern "C" void sfCustomSoundStream_setLooping(sfCustomSoundStream *soundStream, bool loop) { + soundStream->setLooping(loop); } extern "C" float sfCustomSoundStream_getPitch(const sfCustomSoundStream *soundStream) { return soundStream->getPitch(); } +extern "C" float sfCustomSoundStream_getPan(const sfCustomSoundStream *soundStream) { + return soundStream->getPan(); +} + extern "C" float sfCustomSoundStream_getVolume(const sfCustomSoundStream *soundStream) { return soundStream->getVolume(); } +extern "C" bool sfCustomSoundStream_isSpatializationEnabled(const sfCustomSoundStream *soundStream) { + return soundStream->isSpatializationEnabled(); +} + extern "C" sfVector3f sfCustomSoundStream_getPosition(const sfCustomSoundStream *soundStream) { - sf::Vector3f pos = soundStream->getPosition(); - return {pos.x, pos.y, pos.z}; + return convertVector3(soundStream->getPosition()); +} + +extern "C" sfVector3f sfCustomSoundStream_getDirection(const sfCustomSoundStream *soundStream) { + return convertVector3(soundStream->getDirection()); +} + +extern "C" sfSoundSourceCone sfCustomSoundStream_getCone(const sfCustomSoundStream *soundStream) { + return convertCone(soundStream->getCone()); +} + +extern "C" sfVector3f sfCustomSoundStream_getVelocity(const sfCustomSoundStream *soundStream) { + return convertVector3(soundStream->getVelocity()); +} + +extern "C" float sfCustomSoundStream_getDopplerFactor(const sfCustomSoundStream *soundStream) { + return soundStream->getDopplerFactor(); +} + +extern "C" float sfCustomSoundStream_getDirectionalAttenuationFactor(const sfCustomSoundStream *soundStream) { + return soundStream->getDirectionalAttenuationFactor(); } extern "C" bool sfCustomSoundStream_isRelativeToListener(const sfCustomSoundStream *soundStream) { @@ -121,14 +202,56 @@ extern "C" float sfCustomSoundStream_getMinDistance(const sfCustomSoundStream *s return soundStream->getMinDistance(); } +extern "C" float sfCustomSoundStream_getMaxDistance(const sfCustomSoundStream *soundStream) { + return soundStream->getMaxDistance(); +} + +extern "C" float sfCustomSoundStream_getMinGain(const sfCustomSoundStream *soundStream) { + return soundStream->getMinGain(); +} + +extern "C" float sfCustomSoundStream_getMaxGain(const sfCustomSoundStream *soundStream) { + return soundStream->getMaxGain(); +} + extern "C" float sfCustomSoundStream_getAttenuation(const sfCustomSoundStream *soundStream) { return soundStream->getAttenuation(); } -extern "C" bool sfCustomSoundStream_getLoop(const sfCustomSoundStream *soundStream) { - return soundStream->getLoop(); +extern "C" bool sfCustomSoundStream_isLooping(const sfCustomSoundStream *soundStream) { + return soundStream->isLooping(); } extern "C" int64_t sfCustomSoundStream_getPlayingOffset(const sfCustomSoundStream *soundStream) { return soundStream->getPlayingOffset().asMicroseconds(); } + +static std::map> processors; +static std::mutex processorMutex; + +extern "C" void sfCustomSoundStream_setEffectProcessor(sfCustomSoundStream *soundStream, sfEffectProcessor effectProcessor, void *userData) { + std::unique_lock lock(processorMutex); + if (!effectProcessor) { + processors.erase(soundStream); + soundStream->setEffectProcessor(nullptr); + } else { + processors[soundStream] = {effectProcessor, userData}; + soundStream->setEffectProcessor( + [soundStream](const float *inputFrames, + unsigned int &inputFrameCount, + float *outputFrames, + unsigned int &outputFrameCount, + unsigned int frameChannelCount) { + std::unique_lock lock(processorMutex); + auto it = processors.find(soundStream); + if (it != processors.end()) { + it->second.first(inputFrames, &inputFrameCount, outputFrames, &outputFrameCount, frameChannelCount, it->second.second); + } + }); + } +} + +extern "C" void sfCustomSoundStream_del(sfCustomSoundStream *music) { + sfCustomSoundStream_setEffectProcessor(music, nullptr, nullptr); + delete music; +} diff --git a/CSFML/src/Audio/EffectProcessor.hpp b/CSFML/src/Audio/EffectProcessor.hpp new file mode 100644 index 00000000..b554e6b7 --- /dev/null +++ b/CSFML/src/Audio/EffectProcessor.hpp @@ -0,0 +1,8 @@ +#pragma once + +typedef void (*sfEffectProcessor)(const float *inputFrames, + unsigned int *inputFrameCount, + float *outputFrames, + unsigned int *outputFrameCount, + unsigned int frameChannelCount, + void *user_data); diff --git a/CSFML/src/Audio/Listener.cpp b/CSFML/src/Audio/Listener.cpp index 63c3b3b5..9e43073e 100644 --- a/CSFML/src/Audio/Listener.cpp +++ b/CSFML/src/Audio/Listener.cpp @@ -1,6 +1,27 @@ #include "System/Vector3.hpp" #include +typedef struct +{ + float innerAngle; //!< Inner angle, in degrees + float outerAngle; //!< Outer angle, in degrees + float outerGain; //!< Outer gain +} sfListenerCone; + +//////////////////////////////////////////////////////////// +// Convert sf::Listener::Cone to sfListenerCone +//////////////////////////////////////////////////////////// +[[nodiscard]] inline sfListenerCone convertCone(const sf::Listener::Cone cone) { + return {cone.innerAngle.asDegrees(), cone.outerAngle.asDegrees(), cone.outerGain}; +} + +//////////////////////////////////////////////////////////// +// Convert sfVector3f to sf::Vector3f +//////////////////////////////////////////////////////////// +[[nodiscard]] inline sf::Listener::Cone convertCone(const sfListenerCone cone) { + return {sf::degrees(cone.innerAngle), sf::degrees(cone.outerAngle), cone.outerGain}; +} + extern "C" void sfListener_setGlobalVolume(float volume) { sf::Listener::setGlobalVolume(volume); } @@ -10,7 +31,7 @@ extern "C" float sfListener_getGlobalVolume(void) { } extern "C" void sfListener_setPosition(sfVector3f position) { - sf::Listener::setPosition(position.x, position.y, position.z); + sf::Listener::setPosition(convertVector3(position)); } extern "C" sfVector3f sfListener_getPosition() { @@ -19,19 +40,33 @@ extern "C" sfVector3f sfListener_getPosition() { } extern "C" void sfListener_setDirection(sfVector3f direction) { - sf::Listener::setDirection(direction.x, direction.y, direction.z); + sf::Listener::setDirection(convertVector3(direction)); } extern "C" sfVector3f sfListener_getDirection() { - sf::Vector3f dir = sf::Listener::getDirection(); - return {dir.x, dir.y, dir.z}; + return convertVector3(sf::Listener::getDirection()); } extern "C" void sfListener_setUpVector(sfVector3f upVector) { - sf::Listener::setUpVector(upVector.x, upVector.y, upVector.z); + sf::Listener::setUpVector(convertVector3(upVector)); } extern "C" sfVector3f sfListener_getUpVector() { - sf::Vector3f vec = sf::Listener::getUpVector(); - return {vec.x, vec.y, vec.z}; + return convertVector3(sf::Listener::getUpVector()); +} + +extern "C" void sfListener_setVelocity(sfVector3f velocity) { + sf::Listener::setVelocity(convertVector3(velocity)); +} + +extern "C" sfVector3f sfListener_getVelocity() { + return convertVector3(sf::Listener::getVelocity()); +} + +extern "C" void sfListener_setCone(sfListenerCone cone) { + sf::Listener::setCone(convertCone(cone)); +} + +extern "C" sfListenerCone sfListener_getCone() { + return convertCone(sf::Listener::getCone()); } diff --git a/CSFML/src/Audio/Music.cpp b/CSFML/src/Audio/Music.cpp index 7e388412..0fe33c19 100644 --- a/CSFML/src/Audio/Music.cpp +++ b/CSFML/src/Audio/Music.cpp @@ -1,7 +1,13 @@ +#include "Audio/EffectProcessor.hpp" +#include "Audio/SoundSourceCone.hpp" +#include "Audio/SoundStatus.hpp" +#include "SFML/Audio/SoundChannel.hpp" #include "System/InputStreamHelper.hpp" #include "System/Vector3.hpp" #include #include +#include +#include struct sfTimeSpan { int64_t offset; @@ -12,12 +18,8 @@ extern "C" sf::Music *sfMusic_new() { return new sf::Music; } -extern "C" void sfMusic_del(sf::Music *music) { - delete music; -} - extern "C" bool sfMusic_openFromFile(sf::Music *music, const char *filename) { - return music->openFromFile(filename); + return music->openFromFile(std::filesystem::path(filename)); } extern "C" bool sfMusic_openFromMemory(sf::Music *music, const uint8_t *data, size_t sizeInBytes) { @@ -28,12 +30,12 @@ extern "C" bool sfMusic_openFromStream(sf::Music *music, sfInputStreamHelper *st return music->openFromStream(*stream); } -extern "C" void sfMusic_setLoop(sf::Music *music, bool loop) { - music->setLoop(loop != 0); +extern "C" void sfMusic_setLooping(sf::Music *music, bool loop) { + music->setLooping(loop != 0); } -extern "C" bool sfMusic_getLoop(const sf::Music *music) { - return music->getLoop(); +extern "C" bool sfMusic_isLooping(const sf::Music *music) { + return music->isLooping(); } extern "C" int64_t sfMusic_getDuration(const sf::Music *music) { @@ -46,8 +48,8 @@ extern "C" sfTimeSpan sfMusic_getLoopPoints(const sf::Music *music) { } extern "C" void sfMusic_setLoopPoints(sf::Music *music, sfTimeSpan timePoints) { - music->setLoopPoints(sf::Music::TimeSpan(sf::microseconds(timePoints.offset), - sf::microseconds(timePoints.length))); + music->setLoopPoints({sf::microseconds(timePoints.offset), + sf::microseconds(timePoints.length)}); } extern "C" void sfMusic_play(sf::Music *music) { @@ -70,9 +72,12 @@ extern "C" unsigned int sfMusic_getSampleRate(const sf::Music *music) { return music->getSampleRate(); } -extern "C" sf::Music::Status sfMusic_getStatus(const sf::Music *music) { +extern "C" const std::vector *sfMusic_getChannelMap(const sf::Music *music) { + return new std::vector(music->getChannelMap()); +} - return music->getStatus(); +extern "C" sfSoundStatus sfMusic_getStatus(const sf::Music *music) { + return static_cast(music->getStatus()); } extern "C" int64_t sfMusic_getPlayingOffset(const sf::Music *music) { @@ -83,12 +88,40 @@ extern "C" void sfMusic_setPitch(sf::Music *music, float pitch) { music->setPitch(pitch); } +extern "C" void sfMusic_setPan(sf::Music *music, float pan) { + music->setPan(pan); +} + extern "C" void sfMusic_setVolume(sf::Music *music, float volume) { music->setVolume(volume); } -extern "C" void sfMusic_setPosition(sf::Music *music, sfVector3f position) { - music->setPosition(sf::Vector3f(position.x, position.y, position.z)); +extern "C" void sfMusic_setSpatializationEnabled(sf::Music *music, bool enabled) { + music->setSpatializationEnabled(enabled); +} + +extern "C" void sfMusic_setDirection(sf::Music *music, sfVector3f direction) { + music->setDirection({direction.x, direction.y, direction.z}); +} + +extern "C" void sfMusic_setCone(sf::Music *music, sfSoundSourceCone cone) { + music->setCone(convertCone(cone)); +} + +extern "C" void sfMusic_setVelocity(sf::Music *music, sfVector3f velocity) { + music->setVelocity(convertVector3(velocity)); +} + +extern "C" void sfMusic_setDopplerFactor(sf::Music *music, float factor) { + music->setDopplerFactor(factor); +} + +extern "C" void sfMusic_setDirectionalAttenuationFactor(sf::Music *music, float factor) { + music->setDirectionalAttenuationFactor(factor); +} + +extern "C" void sfMusic_setPosition(sf::Music *music, sf::Vector3f position) { + music->setPosition(position); } extern "C" void sfMusic_setRelativeToListener(sf::Music *music, bool relative) { @@ -99,6 +132,18 @@ extern "C" void sfMusic_setMinDistance(sf::Music *music, float distance) { music->setMinDistance(distance); } +extern "C" void sfMusic_setMaxDistance(sf::Music *music, float distance) { + music->setMaxDistance(distance); +} + +extern "C" void sfMusic_setMinGain(sf::Music *music, float gain) { + music->setMinGain(gain); +} + +extern "C" void sfMusic_setMaxGain(sf::Music *music, float gain) { + music->setMaxGain(gain); +} + extern "C" void sfMusic_setAttenuation(sf::Music *music, float attenuation) { music->setAttenuation(attenuation); } @@ -111,15 +156,43 @@ extern "C" float sfMusic_getPitch(const sf::Music *music) { return music->getPitch(); } +extern "C" float sfMusic_getPan(const sf::Music *music) { + return music->getPan(); +} + extern "C" float sfMusic_getVolume(const sf::Music *music) { return music->getVolume(); } +extern "C" bool sfMusic_isSpatializationEnabled(const sf::Music *music) { + return music->isSpatializationEnabled(); +} + extern "C" sfVector3f sfMusic_getPosition(const sf::Music *music) { sf::Vector3f pos = music->getPosition(); return {pos.x, pos.y, pos.z}; } +extern "C" sfVector3f sfMusic_getDirection(const sf::Music *music) { + return convertVector3(music->getDirection()); +} + +extern "C" sfSoundSourceCone sfMusic_getCone(const sf::Music *music) { + return convertCone(music->getCone()); +} + +extern "C" sfVector3f sfMusic_getVelocity(const sf::Music *music) { + return convertVector3(music->getVelocity()); +} + +extern "C" float sfMusic_getDopplerFactor(const sf::Music *music) { + return music->getDopplerFactor(); +} + +extern "C" float sfMusic_getDirectionalAttenuationFactor(const sf::Music *music) { + return music->getDirectionalAttenuationFactor(); +} + extern "C" bool sfMusic_isRelativeToListener(const sf::Music *music) { return music->isRelativeToListener(); } @@ -128,6 +201,48 @@ extern "C" float sfMusic_getMinDistance(const sf::Music *music) { return music->getMinDistance(); } +extern "C" float sfMusic_getMaxDistance(const sf::Music *music) { + return music->getMaxDistance(); +} + +extern "C" float sfMusic_getMinGain(const sf::Music *music) { + return music->getMinGain(); +} + +extern "C" float sfMusic_getMaxGain(const sf::Music *music) { + return music->getMinGain(); +} + extern "C" float sfMusic_getAttenuation(const sf::Music *music) { return music->getAttenuation(); } + +static std::map> processors; +static std::mutex processorMutex; + +extern "C" void sfMusic_setEffectProcessor(sf::Music *music, sfEffectProcessor effectProcessor, void *userData) { + std::unique_lock lock(processorMutex); + if (!effectProcessor) { + processors.erase(music); + music->setEffectProcessor(nullptr); + } else { + processors[music] = {effectProcessor, userData}; + music->setEffectProcessor( + [music](const float *inputFrames, + unsigned int &inputFrameCount, + float *outputFrames, + unsigned int &outputFrameCount, + unsigned int frameChannelCount) { + std::unique_lock lock(processorMutex); + auto it = processors.find(music); + if (it != processors.end()) { + it->second.first(inputFrames, &inputFrameCount, outputFrames, &outputFrameCount, frameChannelCount, it->second.second); + } + }); + } +} + +extern "C" void sfMusic_del(sf::Music *music) { + sfMusic_setEffectProcessor(music, nullptr, nullptr); + delete music; +} diff --git a/CSFML/src/Audio/Sound.cpp b/CSFML/src/Audio/Sound.cpp index 08d9f570..011f4991 100644 --- a/CSFML/src/Audio/Sound.cpp +++ b/CSFML/src/Audio/Sound.cpp @@ -1,19 +1,22 @@ #include "System/Vector3.hpp" -#include +#include "Audio/SoundSourceCone.hpp" +#include "Audio/EffectProcessor.hpp" +#include "Audio/SoundStatus.hpp" +#include +#include +#include #include +#include +#include -extern "C" sf::Sound *sfSound_new(void) { - return new sf::Sound; +extern "C" sf::Sound *sfSound_new(const sf::SoundBuffer *buffer) { + return new sf::Sound(*buffer); } extern "C" sf::Sound *sfSound_cpy(const sf::Sound *sound) { return new sf::Sound(*sound); } -extern "C" void sfSound_del(sf::Sound *sound) { - delete sound; -} - extern "C" void sfSound_play(sf::Sound *sound) { sound->play(); } @@ -31,34 +34,61 @@ extern "C" void sfSound_setBuffer(sf::Sound *sound, const sf::SoundBuffer *buffe } extern "C" const sf::SoundBuffer *sfSound_getBuffer(const sf::Sound *sound) { - const sf::Sound *s = sound; - return s->getBuffer(); + return &sound->getBuffer(); } -extern "C" void sfSound_setLoop(sf::Sound *sound, bool loop) { - sound->setLoop(loop); +extern "C" void sfSound_setLooping(sf::Sound *sound, bool loop) { + sound->setLooping(loop); } -extern "C" bool sfSound_getLoop(const sf::Sound *sound) { - return sound->getLoop(); +extern "C" bool sfSound_isLooping(const sf::Sound *sound) { + return sound->isLooping(); } -extern "C" sf::Sound::Status sfSound_getStatus(const sf::Sound *sound) { - return sound->getStatus(); +extern "C" sfSoundStatus sfSound_getStatus(const sf::Sound *sound) { + return static_cast(sound->getStatus()); } extern "C" void sfSound_setPitch(sf::Sound *sound, float pitch) { sound->setPitch(pitch); } +extern "C" void sfSound_setPan(sf::Sound *sound, float pan) { + sound->setPan(pan); +} + extern "C" void sfSound_setVolume(sf::Sound *sound, float volume) { sound->setVolume(volume); } +extern "C" void sfSound_setSpatializationEnabled(sf::Sound *sound, bool enabled) { + sound->setSpatializationEnabled(enabled); +} + extern "C" void sfSound_setPosition(sf::Sound *sound, sfVector3f position) { sound->setPosition(sf::Vector3f(position.x, position.y, position.z)); } +extern "C" void sfSound_setDirection(sf::Sound *sound, sfVector3f direction) { + sound->setDirection(convertVector3(direction)); +} + +extern "C" void sfSound_setCone(sf::Sound *sound, sfSoundSourceCone cone) { + sound->setCone(convertCone(cone)); +} + +extern "C" void sfSound_setVelocity(sf::Sound *sound, sfVector3f velocity) { + sound->setVelocity(convertVector3(velocity)); +} + +extern "C" void sfSound_setDopplerFactor(sf::Sound *sound, float factor) { + sound->setDopplerFactor(factor); +} + +extern "C" void sfSound_setDirectionalAttenuationFactor(sf::Sound *sound, float factor) { + sound->setDirectionalAttenuationFactor(factor); +} + extern "C" void sfSound_setRelativeToListener(sf::Sound *sound, bool relative) { sound->setRelativeToListener(relative); } @@ -67,25 +97,77 @@ extern "C" void sfSound_setMinDistance(sf::Sound *sound, float distance) { sound->setMinDistance(distance); } +extern "C" void sfSound_setMaxDistance(sf::Sound *sound, float distance) { + assert(sound); + sound->setMaxDistance(distance); +} + +extern "C" void sfSound_setMinGain(sf::Sound *sound, float gain) { + sound->setMinGain(gain); +} + +extern "C" void sfSound_setMaxGain(sf::Sound *sound, float gain) { + sound->setMaxGain(gain); +} + extern "C" void sfSound_setAttenuation(sf::Sound *sound, float attenuation) { sound->setAttenuation(attenuation); } extern "C" void sfSound_setPlayingOffset(sf::Sound *sound, int64_t timeOffset) { - sound->setPlayingOffset(sf::microseconds(timeOffset)); + sound->setPlayingOffset(std::chrono::microseconds(timeOffset)); } extern "C" float sfSound_getPitch(const sf::Sound *sound) { return sound->getPitch(); } +extern "C" float sfSound_getPan(const sf::Sound *sound) { + return sound->getPan(); +} + extern "C" float sfSound_getVolume(const sf::Sound *sound) { return sound->getVolume(); } +extern "C" bool sfSound_isSpatializationEnabled(const sf::Sound *sound) { + return sound->isSpatializationEnabled(); +} + extern "C" sfVector3f sfSound_getPosition(const sf::Sound *sound) { - sf::Vector3f pos = sound->getPosition(); - return {pos.x, pos.y, pos.z}; + return convertVector3(sound->getPosition()); +} + +extern "C" sfVector3f sfSound_getDirection(const sf::Sound *sound) { + return convertVector3(sound->getPosition()); +} + +extern "C" sfSoundSourceCone sfSound_getCone(const sf::Sound *sound) { + return convertCone(sound->getCone()); +} + +extern "C" sfVector3f sfSound_getVelocity(const sf::Sound *sound) { + return convertVector3(sound->getVelocity()); +} + +extern "C" float sfSound_getDopplerFactor(const sf::Sound *sound) { + return sound->getDopplerFactor(); +} + +extern "C" float sfSound_getDirectionalAttenuationFactor(const sf::Sound *sound) { + return sound->getDopplerFactor(); +} + +extern "C" float sfSound_getMaxDistance(const sf::Sound *sound) { + return sound->getMaxDistance(); +} + +extern "C" float sfSound_getMinGain(const sf::Sound *sound) { + return sound->getMinGain(); +} + +extern "C" float sfSound_getMaxGain(const sf::Sound *sound) { + return sound->getMaxGain(); } extern "C" bool sfSound_isRelativeToListener(const sf::Sound *sound) { @@ -104,3 +186,33 @@ extern "C" int64_t sfSound_getPlayingOffset(const sf::Sound *sound) { int64_t time = sound->getPlayingOffset().asMicroseconds(); return time; } + +static std::map> processors; +static std::mutex processorMutex; + +extern "C" void sfSound_setEffectProcessor(sf::Sound *sound, sfEffectProcessor effectProcessor, void *userData) { + std::unique_lock lock(processorMutex); + if (!effectProcessor) { + processors.erase(sound); + sound->setEffectProcessor(nullptr); + } else { + processors[sound] = {effectProcessor, userData}; + sound->setEffectProcessor( + [sound](const float *inputFrames, + unsigned int &inputFrameCount, + float *outputFrames, + unsigned int &outputFrameCount, + unsigned int frameChannelCount) { + std::unique_lock lock(processorMutex); + auto it = processors.find(sound); + if (it != processors.end()) { + it->second.first(inputFrames, &inputFrameCount, outputFrames, &outputFrameCount, frameChannelCount, it->second.second); + } + }); + } +} + +extern "C" void sfSound_del(sf::Sound *music) { + sfSound_setEffectProcessor(music, nullptr, nullptr); + delete music; +} diff --git a/CSFML/src/Audio/SoundBuffer.cpp b/CSFML/src/Audio/SoundBuffer.cpp index a611661e..c8fc9e07 100644 --- a/CSFML/src/Audio/SoundBuffer.cpp +++ b/CSFML/src/Audio/SoundBuffer.cpp @@ -1,4 +1,6 @@ +#include "SFML/Audio/SoundChannel.hpp" #include "System/InputStreamHelper.hpp" +#include "Audio/SoundChannel.hpp" #include #include @@ -26,8 +28,12 @@ extern "C" bool sfSoundBuffer_loadFromStream(sf::SoundBuffer *buffer, sfInputStr return buffer->loadFromStream(*stream); } -extern "C" bool sfSoundBuffer_loadFromSamples(sf::SoundBuffer *buffer, const int16_t *samples, uint64_t sampleCount, unsigned int channelCount, unsigned int sampleRate) { - return buffer->loadFromSamples(samples, sampleCount, channelCount, sampleRate); +extern "C" bool sfSoundBuffer_loadFromSamples(sf::SoundBuffer *buffer, const int16_t *samples, uint64_t sampleCount, unsigned int channelCount, unsigned int sampleRate, const sfSoundChannel *channelMap, size_t channelMapLen) { + std::vector castedChannelMap(channelMapLen); + for (size_t i = 0; i < channelMapLen; i++) { + castedChannelMap.push_back(static_cast(channelMap[i])); + } + return buffer->loadFromSamples(samples, sampleCount, channelCount, sampleRate, castedChannelMap); } extern "C" bool sfSoundBuffer_saveToFile(const sf::SoundBuffer *soundBuffer, const char *filename) { @@ -50,6 +56,10 @@ extern "C" unsigned int sfSoundBuffer_getChannelCount(const sf::SoundBuffer *sou return soundBuffer->getChannelCount(); } +extern "C" const std::vector *sfSoundBuffer_getChannelMap(const sf::SoundBuffer *soundStream) { + return new std::vector(soundStream->getChannelMap()); +} + extern "C" int64_t sfSoundBuffer_getDuration(const sf::SoundBuffer *soundBuffer) { return soundBuffer->getDuration().asMicroseconds(); } diff --git a/CSFML/src/Audio/SoundBufferRecorder.cpp b/CSFML/src/Audio/SoundBufferRecorder.cpp index d0914bfb..78c0b12d 100644 --- a/CSFML/src/Audio/SoundBufferRecorder.cpp +++ b/CSFML/src/Audio/SoundBufferRecorder.cpp @@ -31,3 +31,11 @@ extern "C" bool sfSoundBufferRecorder_setDevice(sf::SoundBufferRecorder *soundBu extern "C" const std::string *sfSoundBufferRecorder_getDevice(sf::SoundBufferRecorder *soundBufferRecorder) { return &soundBufferRecorder->getDevice(); } + +extern "C" void sfSoundBufferRecorder_setChannelCount(sf::SoundBufferRecorder *soundBufferRecorder, unsigned int channelCount) { + soundBufferRecorder->setChannelCount(channelCount); +} + +extern "C" unsigned int sfSoundBufferRecorder_getChannelCount(const sf::SoundBufferRecorder *soundBufferRecorder) { + return soundBufferRecorder->getChannelCount(); +} diff --git a/CSFML/src/Audio/SoundChannel.cpp b/CSFML/src/Audio/SoundChannel.cpp new file mode 100644 index 00000000..a5152fbe --- /dev/null +++ b/CSFML/src/Audio/SoundChannel.cpp @@ -0,0 +1,15 @@ +#include "Audio/SoundChannel.hpp" +#include +#include + +extern "C" std::size_t sfSoundChannelVector_getLength(const std::vector *vec) { + return vec->size(); +} + +extern "C" const sf::SoundChannel *sfSoundChannelVector_getData(const std::vector *vec) { + return vec->data(); +} + +extern "C" void sfSoundChannelVector_del(const std::vector *vec) { + delete vec; +} diff --git a/CSFML/src/Audio/SoundChannel.hpp b/CSFML/src/Audio/SoundChannel.hpp new file mode 100644 index 00000000..bfd6f594 --- /dev/null +++ b/CSFML/src/Audio/SoundChannel.hpp @@ -0,0 +1,24 @@ +#pragma once + +enum sfSoundChannel { + Unspecified, + Mono, + FrontLeft, + FrontRight, + FrontCenter, + FrontLeftOfCenter, + FrontRightOfCenter, + LowFrequencyEffects, + BackLeft, + BackRight, + BackCenter, + SideLeft, + SideRight, + TopCenter, + TopFrontLeft, + TopFrontRight, + TopFrontCenter, + TopBackLeft, + TopBackRight, + TopBackCenter +}; diff --git a/CSFML/src/Audio/SoundSourceCone.hpp b/CSFML/src/Audio/SoundSourceCone.hpp new file mode 100644 index 00000000..71142897 --- /dev/null +++ b/CSFML/src/Audio/SoundSourceCone.hpp @@ -0,0 +1,24 @@ +#pragma once + +#include + +typedef struct +{ + float innerAngle; //!< Inner angle, in degrees + float outerAngle; //!< Outer angle, in degrees + float outerGain; //!< Outer gain +} sfSoundSourceCone; + +//////////////////////////////////////////////////////////// +// Convert sf::SoundSource::Cone to sfSoundSourceCone +//////////////////////////////////////////////////////////// +[[nodiscard]] inline sfSoundSourceCone convertCone(const sf::SoundSource::Cone cone) { + return {cone.innerAngle.asDegrees(), cone.outerAngle.asDegrees(), cone.outerGain}; +} + +//////////////////////////////////////////////////////////// +// Convert sfSoundSourceCone to sf::SoundSource::Cone +//////////////////////////////////////////////////////////// +[[nodiscard]] inline sf::SoundSource::Cone convertCone(const sfSoundSourceCone cone) { + return {sf::degrees(cone.innerAngle), sf::degrees(cone.outerAngle), cone.outerGain}; +} diff --git a/CSFML/src/Audio/SoundStatus.hpp b/CSFML/src/Audio/SoundStatus.hpp new file mode 100644 index 00000000..0979fc1c --- /dev/null +++ b/CSFML/src/Audio/SoundStatus.hpp @@ -0,0 +1,7 @@ +#pragma once + +typedef enum { + sfStopped, ///< Sound / music is not playing + sfPaused, ///< Sound / music is paused + sfPlaying ///< Sound / music is playing +} sfSoundStatus; diff --git a/CSFML/src/Graphics/BlendMode.hpp b/CSFML/src/Graphics/BlendMode.hpp new file mode 100644 index 00000000..e5980c9a --- /dev/null +++ b/CSFML/src/Graphics/BlendMode.hpp @@ -0,0 +1,43 @@ +#pragma once +//////////////////////////////////////////////////////////// +/// \brief Enumeration of the blending factors +/// +//////////////////////////////////////////////////////////// +typedef enum { + sfBlendFactorZero, ///< (0, 0, 0, 0) + sfBlendFactorOne, ///< (1, 1, 1, 1) + sfBlendFactorSrcColor, ///< (src.r, src.g, src.b, src.a) + sfBlendFactorOneMinusSrcColor, ///< (1, 1, 1, 1) - (src.r, src.g, src.b, src.a) + sfBlendFactorDstColor, ///< (dst.r, dst.g, dst.b, dst.a) + sfBlendFactorOneMinusDstColor, ///< (1, 1, 1, 1) - (dst.r, dst.g, dst.b, dst.a) + sfBlendFactorSrcAlpha, ///< (src.a, src.a, src.a, src.a) + sfBlendFactorOneMinusSrcAlpha, ///< (1, 1, 1, 1) - (src.a, src.a, src.a, src.a) + sfBlendFactorDstAlpha, ///< (dst.a, dst.a, dst.a, dst.a) + sfBlendFactorOneMinusDstAlpha ///< (1, 1, 1, 1) - (dst.a, dst.a, dst.a, dst.a) +} sfBlendFactor; + +//////////////////////////////////////////////////////////// +/// \brief Enumeration of the blending equations +/// +//////////////////////////////////////////////////////////// +typedef enum { + sfBlendEquationAdd, ///< Pixel = Src * SrcFactor + Dst * DstFactor + sfBlendEquationSubtract, ///< Pixel = Src * SrcFactor - Dst * DstFactor + sfBlendEquationReverseSubtract, ///< Pixel = Dst * DstFactor - Src * SrcFactor + sfBlendEquationMin, ///< Pixel = min(Dst, Src) + sfBlendEquationMax ///< Pixel = max(Dst, Src) +} sfBlendEquation; + +//////////////////////////////////////////////////////////// +/// \brief Blending mode for drawing +/// +//////////////////////////////////////////////////////////// +typedef struct +{ + sfBlendFactor colorSrcFactor; ///< Source blending factor for the color channels + sfBlendFactor colorDstFactor; ///< Destination blending factor for the color channels + sfBlendEquation colorEquation; ///< Blending equation for the color channels + sfBlendFactor alphaSrcFactor; ///< Source blending factor for the alpha channel + sfBlendFactor alphaDstFactor; ///< Destination blending factor for the alpha channel + sfBlendEquation alphaEquation; ///< Blending equation for the alpha channel +} sfBlendMode; diff --git a/CSFML/src/Graphics/CircleShape.cpp b/CSFML/src/Graphics/CircleShape.cpp index b88f5c12..0a3ab4bf 100644 --- a/CSFML/src/Graphics/CircleShape.cpp +++ b/CSFML/src/Graphics/CircleShape.cpp @@ -18,50 +18,47 @@ extern "C" void sfCircleShape_del(sf::CircleShape *shape) { } extern "C" void sfCircleShape_setPosition(sf::CircleShape *shape, sfVector2f position) { - shape->setPosition(position.x, position.y); + shape->setPosition(convertVector2(position)); } extern "C" void sfCircleShape_setRotation(sf::CircleShape *shape, float angle) { - shape->setRotation(angle); + shape->setRotation(sf::degrees(angle)); } extern "C" void sfCircleShape_setScale(sf::CircleShape *shape, sfVector2f scale) { - shape->setScale(scale.x, scale.y); + shape->setScale(convertVector2(scale)); } extern "C" void sfCircleShape_setOrigin(sf::CircleShape *shape, sfVector2f origin) { - shape->setOrigin(origin.x, origin.y); + shape->setOrigin(convertVector2(origin)); } extern "C" sfVector2f sfCircleShape_getPosition(const sf::CircleShape *shape) { - sf::Vector2f vec2 = shape->getPosition(); - return {vec2.x, vec2.y}; + return convertVector2(shape->getPosition()); } extern "C" float sfCircleShape_getRotation(const sf::CircleShape *shape) { - return shape->getRotation(); + return shape->getRotation().asDegrees(); } extern "C" sfVector2f sfCircleShape_getScale(const sf::CircleShape *shape) { - sf::Vector2f vec2 = shape->getScale(); - return {vec2.x, vec2.y}; + return convertVector2(shape->getScale()); } extern "C" sfVector2f sfCircleShape_getOrigin(const sf::CircleShape *shape) { - sf::Vector2f vec2 = shape->getOrigin(); - return {vec2.x, vec2.y}; + return convertVector2(shape->getOrigin()); } extern "C" void sfCircleShape_move(sf::CircleShape *shape, sfVector2f offset) { - shape->move(offset.x, offset.y); + shape->move(convertVector2(offset)); } extern "C" void sfCircleShape_rotate(sf::CircleShape *shape, float angle) { - shape->rotate(angle); + shape->rotate(sf::degrees(angle)); } extern "C" void sfCircleShape_scale(sf::CircleShape *shape, sfVector2f factors) { - shape->scale(factors.x, factors.y); + shape->scale(convertVector2(factors)); } extern "C" sf::Transform const *sfCircleShape_getTransform(const sf::CircleShape *shape) { @@ -77,7 +74,7 @@ extern "C" void sfCircleShape_setTexture(sf::CircleShape *shape, const sf::Textu } extern "C" void sfCircleShape_setTextureRect(sf::CircleShape *shape, sfIntRect rect) { - shape->setTextureRect(sf::IntRect(rect.left, rect.top, rect.width, rect.height)); + shape->setTextureRect({sf::Vector2i(rect.position.x, rect.position.y), sf::Vector2i(rect.size.x, rect.size.y)}); } extern "C" void sfCircleShape_setFillColor(sf::CircleShape *shape, sfColor color) { @@ -97,18 +94,15 @@ extern "C" const sf::Texture *sfCircleShape_getTexture(const sf::CircleShape *sh } extern "C" sfIntRect sfCircleShape_getTextureRect(const sf::CircleShape *shape) { - sf::IntRect rect = shape->getTextureRect(); - return {rect.left, rect.top, rect.width, rect.height}; + return convertRect(shape->getTextureRect()); } extern "C" sfColor sfCircleShape_getFillColor(const sf::CircleShape *shape) { - sf::Color color = shape->getFillColor(); - return {color.r, color.g, color.b, color.a}; + return convertColor(shape->getFillColor()); } extern "C" sfColor sfCircleShape_getOutlineColor(const sf::CircleShape *shape) { - sf::Color color = shape->getOutlineColor(); - return {color.r, color.g, color.b, color.a}; + return convertColor(shape->getOutlineColor()); } extern "C" float sfCircleShape_getOutlineThickness(const sf::CircleShape *shape) { @@ -120,8 +114,11 @@ extern "C" size_t sfCircleShape_getPointCount(const sf::CircleShape *shape) { } extern "C" sfVector2f sfCircleShape_getPoint(const sf::CircleShape *shape, size_t index) { - sf::Vector2f vec2 = shape->getPoint(index); - return {vec2.x, vec2.y}; + return convertVector2(shape->getPoint(index)); +} + +extern "C" sfVector2f sfCircleShape_getGeometricCenter(const sf::CircleShape *shape) { + return convertVector2(shape->getGeometricCenter()); } extern "C" void sfCircleShape_setRadius(sf::CircleShape *shape, float radius) { @@ -137,11 +134,9 @@ extern "C" void sfCircleShape_setPointCount(sf::CircleShape *shape, size_t count } extern "C" sfFloatRect sfCircleShape_getLocalBounds(const sf::CircleShape *shape) { - sf::FloatRect rect = shape->getLocalBounds(); - return {rect.left, rect.top, rect.width, rect.height}; + return convertRect(shape->getLocalBounds()); } extern "C" sfFloatRect sfCircleShape_getGlobalBounds(const sf::CircleShape *shape) { - sf::FloatRect rect = shape->getGlobalBounds(); - return {rect.left, rect.top, rect.width, rect.height}; + return convertRect(shape->getGlobalBounds()); } diff --git a/CSFML/src/Graphics/Color.hpp b/CSFML/src/Graphics/Color.hpp index 5f1ef902..a4bb8e2c 100644 --- a/CSFML/src/Graphics/Color.hpp +++ b/CSFML/src/Graphics/Color.hpp @@ -1,7 +1,5 @@ -#ifndef SFML_COLOR_H -#define SFML_COLOR_H - -#include +#pragma once +#include struct sfColor { uint8_t r; @@ -10,4 +8,16 @@ struct sfColor { uint8_t a; }; -#endif // SFML_COLOR_H +//////////////////////////////////////////////////////////// +// Convert sf::Color to sfColor +//////////////////////////////////////////////////////////// +[[nodiscard]] inline sfColor convertColor(const sf::Color color) { + return {color.r, color.g, color.b, color.a}; +} + +//////////////////////////////////////////////////////////// +// Convert sfColor to sf::Color +//////////////////////////////////////////////////////////// +[[nodiscard]] inline sf::Color convertColor(const sfColor color) { + return {color.r, color.g, color.b, color.a}; +} diff --git a/CSFML/src/Graphics/ConvexShape.cpp b/CSFML/src/Graphics/ConvexShape.cpp index d6016e6d..2dd36294 100644 --- a/CSFML/src/Graphics/ConvexShape.cpp +++ b/CSFML/src/Graphics/ConvexShape.cpp @@ -18,50 +18,47 @@ extern "C" void sfConvexShape_del(sf::ConvexShape *shape) { } extern "C" void sfConvexShape_setPosition(sf::ConvexShape *shape, sfVector2f position) { - shape->setPosition(position.x, position.y); + shape->setPosition(convertVector2(position)); } extern "C" void sfConvexShape_setRotation(sf::ConvexShape *shape, float angle) { - shape->setRotation(angle); + shape->setRotation(sf::degrees(angle)); } extern "C" void sfConvexShape_setScale(sf::ConvexShape *shape, sfVector2f scale) { - shape->setScale(scale.x, scale.y); + shape->setScale(convertVector2(scale)); } extern "C" void sfConvexShape_setOrigin(sf::ConvexShape *shape, sfVector2f origin) { - shape->setOrigin(origin.x, origin.y); + shape->setOrigin(convertVector2(origin)); } extern "C" sfVector2f sfConvexShape_getPosition(const sf::ConvexShape *shape) { - sf::Vector2f vec2 = shape->getPosition(); - return {vec2.x, vec2.y}; + return convertVector2(shape->getPosition()); } extern "C" float sfConvexShape_getRotation(const sf::ConvexShape *shape) { - return shape->getRotation(); + return shape->getRotation().asDegrees(); } extern "C" sfVector2f sfConvexShape_getScale(const sf::ConvexShape *shape) { - sf::Vector2f vec2 = shape->getScale(); - return {vec2.x, vec2.y}; + return convertVector2(shape->getScale()); } extern "C" sfVector2f sfConvexShape_getOrigin(const sf::ConvexShape *shape) { - sf::Vector2f vec2 = shape->getOrigin(); - return {vec2.x, vec2.y}; + return convertVector2(shape->getOrigin()); } extern "C" void sfConvexShape_move(sf::ConvexShape *shape, sfVector2f offset) { - shape->move(offset.x, offset.y); + shape->move(convertVector2(offset)); } extern "C" void sfConvexShape_rotate(sf::ConvexShape *shape, float angle) { - shape->rotate(angle); + shape->rotate(sf::degrees(angle)); } extern "C" void sfConvexShape_scale(sf::ConvexShape *shape, sfVector2f factors) { - shape->scale(factors.x, factors.y); + shape->scale(convertVector2(factors)); } extern "C" sf::Transform const *sfConvexShape_getTransform(const sf::ConvexShape *shape) { @@ -77,15 +74,15 @@ extern "C" void sfConvexShape_setTexture(sf::ConvexShape *shape, const sf::Textu } extern "C" void sfConvexShape_setTextureRect(sf::ConvexShape *shape, sfIntRect rect) { - shape->setTextureRect(sf::IntRect(rect.left, rect.top, rect.width, rect.height)); + shape->setTextureRect(convertRect(rect)); } extern "C" void sfConvexShape_setFillColor(sf::ConvexShape *shape, sfColor color) { - shape->setFillColor(sf::Color(color.r, color.g, color.b, color.a)); + shape->setFillColor(convertColor(color)); } extern "C" void sfConvexShape_setOutlineColor(sf::ConvexShape *shape, sfColor color) { - shape->setOutlineColor(sf::Color(color.r, color.g, color.b, color.a)); + shape->setOutlineColor(convertColor(color)); } extern "C" void sfConvexShape_setOutlineThickness(sf::ConvexShape *shape, float thickness) { @@ -97,18 +94,15 @@ extern "C" const sf::Texture *sfConvexShape_getTexture(const sf::ConvexShape *sh } extern "C" sfIntRect sfConvexShape_getTextureRect(const sf::ConvexShape *shape) { - sf::IntRect rect = shape->getTextureRect(); - return {rect.left, rect.top, rect.width, rect.height}; + return convertRect(shape->getTextureRect()); } extern "C" sfColor sfConvexShape_getFillColor(const sf::ConvexShape *shape) { - sf::Color color = shape->getFillColor(); - return {color.r, color.g, color.b, color.a}; + return convertColor(shape->getFillColor()); } extern "C" sfColor sfConvexShape_getOutlineColor(const sf::ConvexShape *shape) { - sf::Color color = shape->getOutlineColor(); - return {color.r, color.g, color.b, color.a}; + return convertColor(shape->getOutlineColor()); } extern "C" float sfConvexShape_getOutlineThickness(const sf::ConvexShape *shape) { @@ -120,8 +114,11 @@ extern "C" size_t sfConvexShape_getPointCount(const sf::ConvexShape *shape) { } extern "C" sfVector2f sfConvexShape_getPoint(const sf::ConvexShape *shape, size_t index) { - sf::Vector2f vec2 = shape->getPoint(index); - return {vec2.x, vec2.y}; + return convertVector2(shape->getPoint(index)); +} + +extern "C" sfVector2f sfConvexShape_getGeometricCenter(const sf::ConvexShape *shape) { + return convertVector2(shape->getGeometricCenter()); } extern "C" void sfConvexShape_setPointCount(sf::ConvexShape *shape, size_t count) { @@ -129,15 +126,13 @@ extern "C" void sfConvexShape_setPointCount(sf::ConvexShape *shape, size_t count } extern "C" void sfConvexShape_setPoint(sf::ConvexShape *shape, size_t index, sfVector2f point) { - shape->setPoint(index, sf::Vector2f(point.x, point.y)); + shape->setPoint(index, convertVector2(point)); } extern "C" sfFloatRect sfConvexShape_getLocalBounds(const sf::ConvexShape *shape) { - sf::FloatRect rect = shape->getLocalBounds(); - return {rect.left, rect.top, rect.width, rect.height}; + return convertRect(shape->getLocalBounds()); } extern "C" sfFloatRect sfConvexShape_getGlobalBounds(const sf::ConvexShape *shape) { - sf::FloatRect rect = shape->getGlobalBounds(); - return {rect.left, rect.top, rect.width, rect.height}; + return convertRect(shape->getGlobalBounds()); } diff --git a/CSFML/src/Graphics/CoordinateType.hpp b/CSFML/src/Graphics/CoordinateType.hpp new file mode 100644 index 00000000..0455bb61 --- /dev/null +++ b/CSFML/src/Graphics/CoordinateType.hpp @@ -0,0 +1,10 @@ +#pragma once + +//////////////////////////////////////////////////////////// +/// \brief Types of texture coordinates that can be used for rendering. +/// +//////////////////////////////////////////////////////////// +typedef enum { + sfCoordinateTypeNormalized, ///< sfTexture coordinates in range [0 .. 1]. + sfCoordinateTypePixels ///< sfTexture coordinates in range [0 .. size]. +} sfCoordinateType; diff --git a/CSFML/src/Graphics/CustomShape.cpp b/CSFML/src/Graphics/CustomShape.cpp index 1204b413..5053e4a2 100644 --- a/CSFML/src/Graphics/CustomShape.cpp +++ b/CSFML/src/Graphics/CustomShape.cpp @@ -1,5 +1,7 @@ #include "Graphics/Color.hpp" #include "Graphics/Rect.hpp" +#include "SFML/System/Angle.hpp" +#include "SFML/System/Vector2.hpp" #include "System/Vector2.hpp" #include #include @@ -23,7 +25,7 @@ class sfCustomShape final : public sf::Shape { virtual sf::Vector2f getPoint(std::size_t index) const final { sfVector2f point = myGetPointCb(index, myUserData); - return sf::Vector2f(point.x, point.y); + return convertVector2(point); } using sf::Shape::update; @@ -45,50 +47,47 @@ extern "C" void sfCustomShape_del(sfCustomShape *shape) { } extern "C" void sfCustomShape_setPosition(sfCustomShape *shape, sfVector2f position) { - shape->setPosition(position.x, position.y); + shape->setPosition(convertVector2(position)); } extern "C" void sfCustomShape_setRotation(sfCustomShape *shape, float angle) { - shape->setRotation(angle); + shape->setRotation(sf::degrees(angle)); } extern "C" void sfCustomShape_setScale(sfCustomShape *shape, sfVector2f scale) { - shape->setScale(scale.x, scale.y); + shape->setScale(convertVector2(scale)); } extern "C" void sfCustomShape_setOrigin(sfCustomShape *shape, sfVector2f origin) { - shape->setOrigin(origin.x, origin.y); + shape->setOrigin(convertVector2(origin)); } extern "C" sfVector2f sfCustomShape_getPosition(const sfCustomShape *shape) { - sf::Vector2f vec2 = shape->getPosition(); - return {vec2.x, vec2.y}; + return convertVector2(shape->getPosition()); } extern "C" float sfCustomShape_getRotation(const sfCustomShape *shape) { - return shape->getRotation(); + return shape->getRotation().asDegrees(); } extern "C" sfVector2f sfCustomShape_getScale(const sfCustomShape *shape) { - sf::Vector2f vec2 = shape->getScale(); - return {vec2.x, vec2.y}; + return convertVector2(shape->getScale()); } extern "C" sfVector2f sfCustomShape_getOrigin(const sfCustomShape *shape) { - sf::Vector2f vec2 = shape->getOrigin(); - return {vec2.x, vec2.y}; + return convertVector2(shape->getOrigin()); } extern "C" void sfCustomShape_move(sfCustomShape *shape, sfVector2f offset) { - shape->move(offset.x, offset.y); + shape->move(convertVector2(offset)); } extern "C" void sfCustomShape_rotate(sfCustomShape *shape, float angle) { - shape->rotate(angle); + shape->rotate(sf::degrees(angle)); } extern "C" void sfCustomShape_scale(sfCustomShape *shape, sfVector2f factors) { - shape->scale(factors.x, factors.y); + shape->scale(convertVector2(factors)); } extern "C" sf::Transform const *sfCustomShape_getTransform(const sfCustomShape *shape) { @@ -104,15 +103,15 @@ extern "C" void sfCustomShape_setTexture(sfCustomShape *shape, const sf::Texture } extern "C" void sfCustomShape_setTextureRect(sfCustomShape *shape, sfIntRect rect) { - shape->setTextureRect(sf::IntRect(rect.left, rect.top, rect.width, rect.height)); + shape->setTextureRect(convertRect(rect)); } extern "C" void sfCustomShape_setFillColor(sfCustomShape *shape, sfColor color) { - shape->setFillColor(sf::Color(color.r, color.g, color.b, color.a)); + shape->setFillColor(convertColor(color)); } extern "C" void sfCustomShape_setOutlineColor(sfCustomShape *shape, sfColor color) { - shape->setOutlineColor(sf::Color(color.r, color.g, color.b, color.a)); + shape->setOutlineColor(convertColor(color)); } extern "C" void sfCustomShape_setOutlineThickness(sfCustomShape *shape, float thickness) { @@ -124,18 +123,15 @@ extern "C" const sf::Texture *sfCustomShape_getTexture(const sfCustomShape *shap } extern "C" sfIntRect sfCustomShape_getTextureRect(const sfCustomShape *shape) { - sf::IntRect rect = shape->getTextureRect(); - return {rect.left, rect.top, rect.width, rect.height}; + return convertRect(shape->getTextureRect()); } extern "C" sfColor sfCustomShape_getFillColor(const sfCustomShape *shape) { - sf::Color color = shape->getFillColor(); - return {color.r, color.g, color.b, color.a}; + return convertColor(shape->getFillColor()); } extern "C" sfColor sfCustomShape_getOutlineColor(const sfCustomShape *shape) { - sf::Color color = shape->getOutlineColor(); - return {color.r, color.g, color.b, color.a}; + return convertColor(shape->getOutlineColor()); } extern "C" float sfCustomShape_getOutlineThickness(const sfCustomShape *shape) { @@ -146,19 +142,20 @@ extern "C" size_t sfCustomShape_getPointCount(const sfCustomShape *shape) { return shape->getPointCount(); } +extern "C" sfVector2f sfCustomShape_getGeometricCenter(const sfCustomShape *shape) { + return convertVector2(shape->getGeometricCenter()); +} + extern "C" sfVector2f sfCustomShape_getPoint(const sfCustomShape *shape, size_t index) { - sf::Vector2f vec2 = shape->getPoint(index); - return {vec2.x, vec2.y}; + return convertVector2(shape->getPoint(index)); } extern "C" sfFloatRect sfCustomShape_getLocalBounds(const sfCustomShape *shape) { - sf::FloatRect rect = shape->getLocalBounds(); - return {rect.left, rect.top, rect.width, rect.height}; + return convertRect(shape->getLocalBounds()); } extern "C" sfFloatRect sfCustomShape_getGlobalBounds(const sfCustomShape *shape) { - sf::FloatRect rect = shape->getGlobalBounds(); - return {rect.left, rect.top, rect.width, rect.height}; + return convertRect(shape->getGlobalBounds()); } extern "C" void sfCustomShape_update(sfCustomShape *shape) { diff --git a/CSFML/src/Graphics/Font.cpp b/CSFML/src/Graphics/Font.cpp index acd91059..0b766ecc 100644 --- a/CSFML/src/Graphics/Font.cpp +++ b/CSFML/src/Graphics/Font.cpp @@ -21,24 +21,28 @@ extern "C" sf::Font *sfFont_cpy(const sf::Font *font) { return new sf::Font(*font); } -extern "C" bool sfFont_loadFromFile(sf::Font *font, const char *filename) { - return font->loadFromFile(filename); +extern "C" bool sfFont_openFromFile(sf::Font *font, const char *filename) { + return font->openFromFile(filename); } -extern "C" bool sfFont_loadFromMemory(sf::Font *font, const uint8_t *data, size_t sizeInBytes) { - return font->loadFromMemory(data, sizeInBytes); +extern "C" bool sfFont_openFromMemory(sf::Font *font, const uint8_t *data, size_t sizeInBytes) { + return font->openFromMemory(data, sizeInBytes); } -extern "C" bool sfFont_loadFromStream(sf::Font *font, sfInputStreamHelper *stream) { - return font->loadFromStream(*stream); +extern "C" bool sfFont_openFromStream(sf::Font *font, sfInputStreamHelper *stream) { + return font->openFromStream(*stream); } extern "C" sfGlyph sfFont_getGlyph(const sf::Font *font, uint32_t codePoint, unsigned int characterSize, bool bold, float outlineThickness) { sf::Glyph glyph = font->getGlyph(codePoint, characterSize, bold, outlineThickness); return { glyph.advance, - {glyph.bounds.left, glyph.bounds.top, glyph.bounds.width, glyph.bounds.height}, - {glyph.textureRect.left, glyph.textureRect.top, glyph.textureRect.width, glyph.textureRect.height}}; + {glyph.bounds.position.x, glyph.bounds.position.y, glyph.bounds.size.x, glyph.bounds.size.y}, + {glyph.textureRect.position.x, glyph.textureRect.position.y, glyph.textureRect.size.x, glyph.textureRect.size.y}}; +} + +extern "C" bool sfFont_hasGlyph(const sf::Font *font, uint32_t codePoint) { + return font->hasGlyph(codePoint); } extern "C" float sfFont_getKerning(const sf::Font *font, uint32_t first, uint32_t second, unsigned int characterSize) { diff --git a/CSFML/src/Graphics/Image.cpp b/CSFML/src/Graphics/Image.cpp index 83b9258d..83ae0e02 100644 --- a/CSFML/src/Graphics/Image.cpp +++ b/CSFML/src/Graphics/Image.cpp @@ -2,8 +2,10 @@ #include "Graphics/Rect.hpp" #include "System/InputStreamHelper.hpp" #include "System/Vector2.hpp" +#include "System/Buffer.hpp" #include #include +#include extern "C" sf::Image *sfImage_new() { return new sf::Image; @@ -17,18 +19,17 @@ extern "C" void sfImage_del(sf::Image *image) { delete image; } -extern "C" void sfImage_create_w_h_color(sf::Image *image, unsigned int width, unsigned int height, sfColor color) { - image->create(width, height, sf::Color(color.r, color.g, color.b, color.a)); +extern "C" void sfImage_resizeWithColor(sf::Image *image, sfVector2u size, sfColor color) { + image->resize(convertVector2(size), convertColor(color)); } -extern "C" void sfImage_create_w_h_pixels(sf::Image *image, unsigned int width, unsigned int height, const uint8_t *data) { - image->create(width, height, data); +extern "C" void sfImage_resizeWithPixels(sf::Image *image, sfVector2u size, const uint8_t *pixels) { + image->resize(convertVector2(size), pixels); } extern "C" bool sfImage_loadFromFile(sf::Image *image, const char *filename) { return image->loadFromFile(filename); } - extern "C" bool sfImage_loadFromMemory(sf::Image *image, const uint8_t *data, size_t sizeInBytes) { return image->loadFromMemory(data, sizeInBytes); } @@ -41,22 +42,27 @@ extern "C" bool sfImage_saveToFile(const sf::Image *image, const char *filename) return image->saveToFile(filename); } +extern "C" sfBuffer *sfImage_saveToMemory(const sf::Image *image, const char *format) { + if (auto data = image->saveToMemory(format)) { + return new sfBuffer{std::move(*data)}; + } + return nullptr; +} + extern "C" void sfImage_createMaskFromColor(sf::Image *image, sfColor colorKey, uint8_t alpha) { - image->createMaskFromColor(sf::Color(colorKey.r, colorKey.g, colorKey.b, colorKey.a), alpha); + image->createMaskFromColor(convertColor(colorKey), alpha); } -extern "C" void sfImage_copy(sf::Image *image, const sf::Image *source, unsigned int destX, unsigned int destY, sfIntRect sourceRect, bool applyAlpha) { - sf::IntRect sfmlRect(sourceRect.left, sourceRect.top, sourceRect.width, sourceRect.height); - image->copy(*source, destX, destY, sfmlRect, applyAlpha); +extern "C" bool sfImage_copy(sf::Image *image, const sf::Image *source, sfVector2u dest, sfIntRect sourceRect, bool applyAlpha) { + return image->copy(*source, convertVector2(dest), convertRect(sourceRect), applyAlpha); } -extern "C" void sfImage_setPixel(sf::Image *image, unsigned int x, unsigned int y, sfColor color) { - image->setPixel(x, y, sf::Color(color.r, color.g, color.b, color.a)); +extern "C" void sfImage_setPixel(sf::Image *image, sfVector2u coords, sfColor color) { + image->setPixel(convertVector2(coords), convertColor(color)); } -extern "C" sfColor sfImage_getPixel(const sf::Image *image, unsigned int x, unsigned int y) { - sf::Color color = image->getPixel(x, y); - return sfColor{color.r, color.g, color.b, color.a}; +extern "C" sfColor sfImage_getPixel(const sf::Image *image, sfVector2u coords) { + return convertColor(image->getPixel(convertVector2(coords))); } extern "C" const uint8_t *sfImage_getPixelsPtr(const sf::Image *image) { @@ -64,8 +70,7 @@ extern "C" const uint8_t *sfImage_getPixelsPtr(const sf::Image *image) { } extern "C" sfVector2u sfImage_getSize(const sf::Image *image) { - sf::Vector2u size = image->getSize(); - return {size.x, size.y}; + return convertVector2(image->getSize()); } extern "C" void sfImage_flipHorizontally(sf::Image *image) { diff --git a/CSFML/src/Graphics/PrimitiveType.hpp b/CSFML/src/Graphics/PrimitiveType.hpp new file mode 100644 index 00000000..409d01ad --- /dev/null +++ b/CSFML/src/Graphics/PrimitiveType.hpp @@ -0,0 +1,10 @@ +#pragma once + +typedef enum { + sfPoints, + sfLines, + sfLineStrip, + sfTriangles, + sfTriangleStrip, + sfTriangleFan, +} sfPrimitiveType; diff --git a/CSFML/src/Graphics/Rect.hpp b/CSFML/src/Graphics/Rect.hpp index 041868f0..45939d94 100644 --- a/CSFML/src/Graphics/Rect.hpp +++ b/CSFML/src/Graphics/Rect.hpp @@ -1,18 +1,33 @@ -#ifndef SFML_RECT_H -#define SFML_RECT_H +#pragma once +#include +#include "System/Vector2.hpp" struct sfFloatRect { - float left; - float top; - float width; - float height; + sfVector2f position; + sfVector2f size; }; struct sfIntRect { - int left; - int top; - int width; - int height; + sfVector2i position; + sfVector2i size; }; -#endif // SFML_RECT_H +//////////////////////////////////////////////////////////// +// Convert sf::Rect to CSFML Rect +//////////////////////////////////////////////////////////// +[[nodiscard]] inline sfFloatRect convertRect(const sf::FloatRect &rect) { + return {{rect.position.x, rect.position.y}, {rect.size.x, rect.size.y}}; +} +[[nodiscard]] inline sfIntRect convertRect(const sf::IntRect &rect) { + return {{rect.position.x, rect.position.y}, {rect.size.x, rect.size.y}}; +} + +//////////////////////////////////////////////////////////// +// Convert CSFML Rect to sf::Rect +//////////////////////////////////////////////////////////// +[[nodiscard]] inline sf::FloatRect convertRect(const sfFloatRect &rect) { + return {{rect.position.x, rect.position.y}, {rect.size.x, rect.size.y}}; +} +[[nodiscard]] inline sf::IntRect convertRect(const sfIntRect &rect) { + return {{rect.position.x, rect.position.y}, {rect.size.x, rect.size.y}}; +} diff --git a/CSFML/src/Graphics/RectangleShape.cpp b/CSFML/src/Graphics/RectangleShape.cpp index 7afa9a5d..bd385ba6 100644 --- a/CSFML/src/Graphics/RectangleShape.cpp +++ b/CSFML/src/Graphics/RectangleShape.cpp @@ -18,50 +18,47 @@ extern "C" void sfRectangleShape_del(sf::RectangleShape *shape) { } extern "C" void sfRectangleShape_setPosition(sf::RectangleShape *shape, sfVector2f position) { - shape->setPosition(position.x, position.y); + shape->setPosition(convertVector2(position)); } extern "C" void sfRectangleShape_setRotation(sf::RectangleShape *shape, float angle) { - shape->setRotation(angle); + shape->setRotation(sf::degrees(angle)); } extern "C" void sfRectangleShape_setScale(sf::RectangleShape *shape, sfVector2f scale) { - shape->setScale(scale.x, scale.y); + shape->setScale(convertVector2(scale)); } extern "C" void sfRectangleShape_setOrigin(sf::RectangleShape *shape, sfVector2f origin) { - shape->setOrigin(origin.x, origin.y); + shape->setOrigin(convertVector2(origin)); } extern "C" sfVector2f sfRectangleShape_getPosition(const sf::RectangleShape *shape) { - sf::Vector2f vec2 = shape->getPosition(); - return {vec2.x, vec2.y}; + return convertVector2(shape->getPosition()); } extern "C" float sfRectangleShape_getRotation(const sf::RectangleShape *shape) { - return shape->getRotation(); + return shape->getRotation().asDegrees(); } extern "C" sfVector2f sfRectangleShape_getScale(const sf::RectangleShape *shape) { - sf::Vector2f vec2 = shape->getScale(); - return {vec2.x, vec2.y}; + return convertVector2(shape->getScale()); } extern "C" sfVector2f sfRectangleShape_getOrigin(const sf::RectangleShape *shape) { - sf::Vector2f vec2 = shape->getOrigin(); - return {vec2.x, vec2.y}; + return convertVector2(shape->getOrigin()); } extern "C" void sfRectangleShape_move(sf::RectangleShape *shape, sfVector2f offset) { - shape->move(offset.x, offset.y); + shape->move(convertVector2(offset)); } extern "C" void sfRectangleShape_rotate(sf::RectangleShape *shape, float angle) { - shape->rotate(angle); + shape->rotate(sf::degrees(angle)); } extern "C" void sfRectangleShape_scale(sf::RectangleShape *shape, sfVector2f factors) { - shape->scale(factors.x, factors.y); + shape->scale(convertVector2(factors)); } extern "C" sf::Transform const *sfRectangleShape_getTransform(const sf::RectangleShape *shape) { @@ -77,15 +74,15 @@ extern "C" void sfRectangleShape_setTexture(sf::RectangleShape *shape, const sf: } extern "C" void sfRectangleShape_setTextureRect(sf::RectangleShape *shape, sfIntRect rect) { - shape->setTextureRect(sf::IntRect(rect.left, rect.top, rect.width, rect.height)); + shape->setTextureRect(convertRect(rect)); } extern "C" void sfRectangleShape_setFillColor(sf::RectangleShape *shape, sfColor color) { - shape->setFillColor(sf::Color(color.r, color.g, color.b, color.a)); + shape->setFillColor(convertColor(color)); } extern "C" void sfRectangleShape_setOutlineColor(sf::RectangleShape *shape, sfColor color) { - shape->setOutlineColor(sf::Color(color.r, color.g, color.b, color.a)); + shape->setOutlineColor(convertColor(color)); } extern "C" void sfRectangleShape_setOutlineThickness(sf::RectangleShape *shape, float thickness) { @@ -97,18 +94,15 @@ extern "C" const sf::Texture *sfRectangleShape_getTexture(const sf::RectangleSha } extern "C" sfIntRect sfRectangleShape_getTextureRect(const sf::RectangleShape *shape) { - sf::IntRect rect = shape->getTextureRect(); - return {rect.left, rect.top, rect.width, rect.height}; + return convertRect(shape->getTextureRect()); } extern "C" sfColor sfRectangleShape_getFillColor(const sf::RectangleShape *shape) { - sf::Color color = shape->getFillColor(); - return {color.r, color.g, color.b, color.a}; + return convertColor(shape->getFillColor()); } extern "C" sfColor sfRectangleShape_getOutlineColor(const sf::RectangleShape *shape) { - sf::Color color = shape->getOutlineColor(); - return {color.r, color.g, color.b, color.a}; + return convertColor(shape->getOutlineColor()); } extern "C" float sfRectangleShape_getOutlineThickness(const sf::RectangleShape *shape) { @@ -120,25 +114,25 @@ extern "C" size_t sfRectangleShape_getPointCount(const sf::RectangleShape *shape } extern "C" sfVector2f sfRectangleShape_getPoint(const sf::RectangleShape *shape, size_t index) { - sf::Vector2f vec2 = shape->getPoint(index); - return {vec2.x, vec2.y}; + return convertVector2(shape->getPoint(index)); +} + +extern "C" sfVector2f sfRectangleShape_getGeometricCenter(const sf::RectangleShape *shape) { + return convertVector2(shape->getGeometricCenter()); } extern "C" void sfRectangleShape_setSize(sf::RectangleShape *shape, sfVector2f size) { - shape->setSize(sf::Vector2f(size.x, size.y)); + shape->setSize(convertVector2(size)); } extern "C" sfVector2f sfRectangleShape_getSize(const sf::RectangleShape *shape) { - sf::Vector2f vec2 = shape->getSize(); - return {vec2.x, vec2.y}; + return convertVector2(shape->getSize()); } extern "C" sfFloatRect sfRectangleShape_getLocalBounds(const sf::RectangleShape *shape) { - sf::FloatRect rect = shape->getLocalBounds(); - return {rect.left, rect.top, rect.width, rect.height}; + return convertRect(shape->getLocalBounds()); } extern "C" sfFloatRect sfRectangleShape_getGlobalBounds(const sf::RectangleShape *shape) { - sf::FloatRect rect = shape->getGlobalBounds(); - return {rect.left, rect.top, rect.width, rect.height}; + return convertRect(shape->getGlobalBounds()); } diff --git a/CSFML/src/Graphics/RenderStates.hpp b/CSFML/src/Graphics/RenderStates.hpp new file mode 100644 index 00000000..733e3ee8 --- /dev/null +++ b/CSFML/src/Graphics/RenderStates.hpp @@ -0,0 +1,20 @@ +//////////////////////////////////////////////////////////// +/// \brief Define the states used for drawing to a RenderTarget +/// +//////////////////////////////////////////////////////////// +#include "Graphics/BlendMode.hpp" +#include "Graphics/CoordinateType.hpp" +#include "Graphics/StencilMode.hpp" +#include "Graphics/Transform.hpp" +#include +#include + +typedef struct +{ + sfBlendMode blendMode; ///< Blending mode + sfStencilMode stencilMode; //!< Stencil mode + sfTransform transform; ///< Transform + sfCoordinateType coordinateType; //!< Texture coordinate type + const sf::Texture *texture; ///< Texture + const sf::Shader *shader; ///< Shader +} sfRenderStates; diff --git a/CSFML/src/Graphics/RenderTexture.cpp b/CSFML/src/Graphics/RenderTexture.cpp index 6dc447d0..edecd635 100644 --- a/CSFML/src/Graphics/RenderTexture.cpp +++ b/CSFML/src/Graphics/RenderTexture.cpp @@ -1,5 +1,7 @@ +#include "Graphics/PrimitiveType.hpp" #include "Graphics/Rect.hpp" #include "Graphics/Color.hpp" +#include "SFML/Graphics/PrimitiveType.hpp" #include "SFML/Window/ContextSettings.hpp" #include "System/Vector2.hpp" #include @@ -9,6 +11,7 @@ #include #include #include +#include "Graphics/StencilMode.hpp" #include extern "C" sf::RenderTexture *sfRenderTexture_new() { @@ -19,13 +22,12 @@ extern "C" void sfRenderTexture_del(sf::RenderTexture *renderTexture) { delete renderTexture; } -extern "C" bool sfRenderTexture_create(sf::RenderTexture *renderTexture, unsigned int width, unsigned int height, const sf::ContextSettings *settings) { - return renderTexture->create(width, height, *settings); +extern "C" bool sfRenderTexture_resize(sf::RenderTexture *texture, sfVector2u size, const sf::ContextSettings *settings) { + return texture->resize(convertVector2(size), *settings); } extern "C" sfVector2u sfRenderTexture_getSize(const sf::RenderTexture *renderTexture) { - sf::Vector2u size = renderTexture->getSize(); - return {size.x, size.y}; + return convertVector2(renderTexture->getSize()); } extern "C" bool sfRenderTexture_isSrgb(const sf::RenderTexture *renderTexture) { @@ -41,7 +43,15 @@ extern "C" void sfRenderTexture_display(sf::RenderTexture *renderTexture) { } extern "C" void sfRenderTexture_clear(sf::RenderTexture *renderTexture, sfColor color) { - renderTexture->clear(sf::Color(color.r, color.g, color.b, color.a)); + renderTexture->clear(convertColor(color)); +} + +extern "C" void sfRenderTexture_clearStencil(sf::RenderTexture *renderTexture, sfStencilValue stencilValue) { + renderTexture->clearStencil(convertStencilValue(stencilValue)); +} + +extern "C" void sfRenderTexture_clearColorAndStencil(sf::RenderTexture *renderTexture, sfColor color, sfStencilValue stencilValue) { + renderTexture->clear(convertColor(color), convertStencilValue(stencilValue)); } extern "C" void sfRenderTexture_setView(sf::RenderTexture *renderTexture, const sf::View *view) { @@ -57,28 +67,27 @@ extern "C" const sf::View *sfRenderTexture_getDefaultView(const sf::RenderTextur } extern "C" sfIntRect sfRenderTexture_getViewport(const sf::RenderTexture *renderTexture, const sf::View *view) { - sf::IntRect rect = renderTexture->getViewport(*view); - return {rect.left, rect.top, rect.width, rect.height}; + return convertRect(renderTexture->getViewport(*view)); +} + +extern "C" sfIntRect sfRenderTexture_getScissor(const sf::RenderTexture *renderTexture, const sf::View *view) { + return convertRect(renderTexture->getScissor(*view)); } extern "C" sfVector2f sfRenderTexture_mapPixelToCoords(const sf::RenderTexture *renderTexture, sfVector2i point) { - sf::Vector2f result = renderTexture->mapPixelToCoords(sf::Vector2i(point.x, point.y)); - return {result.x, result.y}; + return convertVector2(renderTexture->mapPixelToCoords(convertVector2(point))); } extern "C" sfVector2f sfRenderTexture_mapPixelToCoords_View(const sf::RenderTexture *renderTexture, sfVector2i point, const sf::View *targetView) { - sf::Vector2f result = renderTexture->mapPixelToCoords(sf::Vector2i(point.x, point.y), *targetView); - return {result.x, result.y}; + return convertVector2(renderTexture->mapPixelToCoords(convertVector2(point), *targetView)); } extern "C" sfVector2i sfRenderTexture_mapCoordsToPixel(const sf::RenderTexture *renderTexture, sfVector2f point) { - sf::Vector2i result = renderTexture->mapCoordsToPixel(sf::Vector2f(point.x, point.y)); - return {result.x, result.y}; + return convertVector2(renderTexture->mapCoordsToPixel(convertVector2(point))); } extern "C" sfVector2i sfRenderTexture_mapCoordsToPixel_View(const sf::RenderTexture *renderTexture, sfVector2f point, const sf::View *targetView) { - sf::Vector2i result = renderTexture->mapCoordsToPixel(sf::Vector2f(point.x, point.y), *targetView); - return {result.x, result.y}; + return convertVector2(renderTexture->mapCoordsToPixel(convertVector2(point), *targetView)); } extern "C" void sfRenderTexture_drawSprite(sf::RenderTexture *renderTexture, const sf::Sprite *object, const sf::RenderStates *states) { @@ -105,8 +114,8 @@ extern "C" void sfRenderTexture_drawVertexBuffer(sf::RenderTexture *renderTextur extern "C" void sfRenderTexture_drawPrimitives(sf::RenderTexture *renderTexture, const sf::Vertex *vertices, size_t vertexCount, - sf::PrimitiveType type, const sf::RenderStates *states) { - renderTexture->draw(vertices, vertexCount, type, *states); + sfPrimitiveType type, const sf::RenderStates *states) { + renderTexture->draw(vertices, vertexCount, static_cast(type), *states); } extern "C" void sfRenderTexture_pushGLStates(sf::RenderTexture *renderTexture) { @@ -130,7 +139,7 @@ extern "C" void sfRenderTexture_setSmooth(sf::RenderTexture *renderTexture, bool } extern "C" unsigned int sfRenderTexture_getMaximumAntialiasingLevel() { - return sf::RenderTexture::getMaximumAntialiasingLevel(); + return sf::RenderTexture::getMaximumAntiAliasingLevel(); } extern "C" bool sfRenderTexture_isSmooth(const sf::RenderTexture *renderTexture) { diff --git a/CSFML/src/Graphics/RenderWindow.cpp b/CSFML/src/Graphics/RenderWindow.cpp index 8be72feb..d92015be 100644 --- a/CSFML/src/Graphics/RenderWindow.cpp +++ b/CSFML/src/Graphics/RenderWindow.cpp @@ -1,7 +1,14 @@ +#include "Graphics/PrimitiveType.hpp" #include "Graphics/Rect.hpp" #include "Graphics/Color.hpp" +#include "Graphics/StencilMode.hpp" +#include "SFML/Graphics/Color.hpp" +#include "SFML/Graphics/PrimitiveType.hpp" +#include "SFML/Graphics/Rect.hpp" #include "System/Vector2.hpp" +#include "Window/Event.hpp" #include "Window/VideoMode.hpp" +#include "Window/Window.hpp" #include #include #include @@ -11,12 +18,13 @@ #include #include #include +#include #include -extern "C" sf::RenderWindow *sfRenderWindow_new_mtss(sfVideoMode mode, const uint32_t *title, uint32_t style, const sf::ContextSettings *settings) { +extern "C" sf::RenderWindow *sfRenderWindow_new_mtsss(sfVideoMode mode, const uint32_t *title, uint32_t style, sfState state, const sf::ContextSettings *settings) { // Convert video mode - sf::VideoMode videoMode(mode.width, mode.height, mode.bitsPerPixel); - return new sf::RenderWindow(videoMode, title, style, *settings); + sf::VideoMode videoMode(sf::Vector2u(mode.size.x, mode.size.y), mode.bitsPerPixel); + return new sf::RenderWindow(videoMode, (char32_t *)title, style, to_state(state), *settings); } extern "C" sf::RenderWindow *sfRenderWindow_new_handle_settings(sf::WindowHandle handle, const sf::ContextSettings *settings) { @@ -27,13 +35,6 @@ extern "C" void sfRenderWindow_del(sf::RenderWindow *renderWindow) { delete renderWindow; } -extern "C" void sfRenderWindow_create_mtss(sf::RenderWindow *renderWindow, sfVideoMode mode, const uint32_t *title, uint32_t style, const sf::ContextSettings *settings) { - // Convert video mode - sf::VideoMode videoMode(mode.width, mode.height, mode.bitsPerPixel); - // Create the window - renderWindow->create(videoMode, title, style, *settings); -} - extern "C" void sfRenderWindow_close(sf::RenderWindow *renderWindow) { renderWindow->close(); } @@ -46,12 +47,12 @@ extern "C" const sf::ContextSettings *sfRenderWindow_getSettings(const sf::Rende return &renderWindow->getSettings(); } -extern "C" bool sfRenderWindow_pollEvent(sf::RenderWindow *renderWindow, sf::Event *event) { - return renderWindow->pollEvent(*event); +extern "C" bool sfRenderWindow_pollEvent(sf::RenderWindow *renderWindow, sfEvent *event) { + return convertEvent(renderWindow->pollEvent(), *event); } -extern "C" bool sfRenderWindow_waitEvent(sf::RenderWindow *renderWindow, sf::Event *event) { - return renderWindow->waitEvent(*event); +extern "C" bool sfRenderWindow_waitEvent(sf::RenderWindow *renderWindow, sfEvent *event, const int64_t timeout) { + return convertEvent(renderWindow->waitEvent(sf::Time(std::chrono::microseconds(timeout))), *event); } extern "C" sfVector2i sfRenderWindow_getPosition(const sf::RenderWindow *renderWindow) { @@ -69,7 +70,23 @@ extern "C" sfVector2u sfRenderWindow_getSize(const sf::RenderWindow *renderWindo } extern "C" void sfRenderWindow_setSize(sf::RenderWindow *renderWindow, sfVector2u size) { - renderWindow->setSize(sf::Vector2u(size.x, size.y)); + renderWindow->setSize(sf::Vector2u({size.x, size.y})); +} + +extern "C" void sfRenderWindow_setMinimumSize(sf::RenderWindow *renderWindow, const sfVector2u *size) { + if (size == nullptr) { + renderWindow->setMinimumSize(std::nullopt); + } else { + renderWindow->setMinimumSize(std::optional({size->x, size->y})); + } +} + +extern "C" void sfRenderWindow_setMaximumSize(sf::RenderWindow *renderWindow, const sfVector2u *size) { + if (size == nullptr) { + renderWindow->setMaximumSize(std::nullopt); + } else { + renderWindow->setMaximumSize(std::optional({size->x, size->y})); + } } extern "C" bool sfRenderWindow_isSrgb(const sf::RenderWindow *renderWindow) { @@ -77,11 +94,11 @@ extern "C" bool sfRenderWindow_isSrgb(const sf::RenderWindow *renderWindow) { } extern "C" void sfRenderWindow_setUnicodeTitle(sf::RenderWindow *renderWindow, const uint32_t *title) { - renderWindow->setTitle(title); + renderWindow->setTitle((char32_t *)title); } -extern "C" void sfRenderWindow_setIcon(sf::RenderWindow *renderWindow, unsigned int width, unsigned int height, const uint8_t *pixels) { - renderWindow->setIcon(width, height, pixels); +extern "C" void sfRenderWindow_setIcon(sf::RenderWindow *renderWindow, sfVector2u size, const uint8_t *pixels) { + renderWindow->setIcon(sf::Vector2u({size.x, size.y}), pixels); } extern "C" void sfRenderWindow_setVisible(sf::RenderWindow *renderWindow, bool visible) { @@ -132,14 +149,22 @@ extern "C" void sfRenderWindow_setJoystickThreshold(sf::RenderWindow *renderWind renderWindow->setJoystickThreshold(threshold); } -extern "C" sf::WindowHandle sfRenderWindow_getSystemHandle(const sf::RenderWindow *renderWindow) { - return renderWindow->getSystemHandle(); +extern "C" sf::WindowHandle sfRenderWindow_getNativeHandle(const sf::RenderWindow *renderWindow) { + return renderWindow->getNativeHandle(); } extern "C" void sfRenderWindow_clear(sf::RenderWindow *renderWindow, sfColor color) { renderWindow->clear(sf::Color(color.r, color.g, color.b, color.a)); } +extern "C" void sfRenderWindow_clearStencil(sf::RenderWindow *renderWindow, sfStencilValue stencilValue) { + renderWindow->clearStencil(convertStencilValue(stencilValue)); +} + +extern "C" void sfRenderWindow_clearColorAndStencil(sf::RenderWindow *renderWindow, sfColor color, sfStencilValue stencilValue) { + renderWindow->clear(sf::Color(color.r, color.g, color.b, color.a), convertStencilValue(stencilValue)); +} + extern "C" void sfRenderWindow_setView(sf::RenderWindow *renderWindow, const sf::View *view) { renderWindow->setView(*view); } @@ -154,26 +179,31 @@ extern "C" const sf::View *sfRenderWindow_getDefaultView(const sf::RenderWindow extern "C" sfIntRect sfRenderWindow_getViewport(const sf::RenderWindow *renderWindow, const sf::View *view) { sf::IntRect rect = renderWindow->getViewport(*view); - return {rect.left, rect.top, rect.width, rect.height}; + return {rect.position.x, rect.position.y, rect.size.x, rect.size.y}; +} + +extern "C" sfIntRect sfRenderWindow_getScissor(const sf::RenderWindow *renderWindow, const sf::View *view) { + sf::IntRect rect = renderWindow->getViewport(*view); + return {{rect.position.x, rect.position.y}, {rect.size.x, rect.size.y}}; } extern "C" sfVector2f sfRenderWindow_mapPixelToCoords(const sf::RenderWindow *renderWindow, sfVector2i point) { - sf::Vector2f vec2 = renderWindow->mapPixelToCoords(sf::Vector2i(point.x, point.y)); + sf::Vector2f vec2 = renderWindow->mapPixelToCoords(sf::Vector2i({point.x, point.y})); return {vec2.x, vec2.y}; } extern "C" sfVector2f sfRenderWindow_mapPixelToCoords_View(const sf::RenderWindow *renderWindow, sfVector2i point, const sf::View *targetView) { - sf::Vector2f vec2 = renderWindow->mapPixelToCoords(sf::Vector2i(point.x, point.y), *targetView); + sf::Vector2f vec2 = renderWindow->mapPixelToCoords(sf::Vector2i({point.x, point.y}), *targetView); return {vec2.x, vec2.y}; } extern "C" sfVector2i sfRenderWindow_mapCoordsToPixel(const sf::RenderWindow *renderWindow, sfVector2f point) { - sf::Vector2i vec2 = renderWindow->mapCoordsToPixel(sf::Vector2f(point.x, point.y)); + sf::Vector2i vec2 = renderWindow->mapCoordsToPixel(sf::Vector2f({point.x, point.y})); return {vec2.x, vec2.y}; } extern "C" sfVector2i sfRenderWindow_mapCoordsToPixel_View(const sf::RenderWindow *renderWindow, sfVector2f point, const sf::View *targetView) { - sf::Vector2i vec2 = renderWindow->mapCoordsToPixel(sf::Vector2f(point.x, point.y), *targetView); + sf::Vector2i vec2 = renderWindow->mapCoordsToPixel(sf::Vector2f({point.x, point.y}), *targetView); return {vec2.x, vec2.y}; } @@ -201,8 +231,8 @@ extern "C" void sfRenderWindow_drawVertexBuffer(sf::RenderWindow *renderWindow, extern "C" void sfRenderWindow_drawPrimitives(sf::RenderWindow *renderWindow, const sf::Vertex *vertices, size_t vertexCount, - sf::PrimitiveType type, const sf::RenderStates *states) { - renderWindow->draw(vertices, vertexCount, type, *states); + sfPrimitiveType type, const sf::RenderStates *states) { + renderWindow->draw(vertices, vertexCount, static_cast(type), *states); } extern "C" void sfRenderWindow_pushGLStates(sf::RenderWindow *renderWindow) { diff --git a/CSFML/src/Graphics/Sprite.cpp b/CSFML/src/Graphics/Sprite.cpp index d0a25ec5..3ba374ed 100644 --- a/CSFML/src/Graphics/Sprite.cpp +++ b/CSFML/src/Graphics/Sprite.cpp @@ -1,12 +1,13 @@ #include "Graphics/Color.hpp" #include "Graphics/Rect.hpp" +#include "SFML/System/Vector2.hpp" #include "System/Vector2.hpp" #include #include #include -extern "C" sf::Sprite *sfSprite_new(void) { - return new sf::Sprite; +extern "C" sf::Sprite *sfSprite_new(const sf::Texture *texture, const sfIntRect rect) { + return new sf::Sprite(*texture, convertRect(rect)); } extern "C" sf::Sprite *sfSprite_cpy(const sf::Sprite *sprite) { @@ -18,50 +19,47 @@ extern "C" void sfSprite_del(sf::Sprite *sprite) { } extern "C" void sfSprite_setPosition(sf::Sprite *sprite, sfVector2f position) { - sprite->setPosition(position.x, position.y); + sprite->setPosition(convertVector2(position)); } extern "C" void sfSprite_setRotation(sf::Sprite *sprite, float angle) { - sprite->setRotation(angle); + sprite->setRotation(sf::degrees(angle)); } extern "C" void sfSprite_setScale(sf::Sprite *sprite, sfVector2f scale) { - sprite->setScale(scale.x, scale.y); + sprite->setScale(convertVector2(scale)); } extern "C" void sfSprite_setOrigin(sf::Sprite *sprite, sfVector2f origin) { - sprite->setOrigin(origin.x, origin.y); + sprite->setOrigin(convertVector2(origin)); } extern "C" sfVector2f sfSprite_getPosition(const sf::Sprite *sprite) { - sf::Vector2f vec2 = sprite->getPosition(); - return {vec2.x, vec2.y}; + return convertVector2(sprite->getPosition()); } extern "C" float sfSprite_getRotation(const sf::Sprite *sprite) { - return sprite->getRotation(); + return sprite->getRotation().asDegrees(); } extern "C" sfVector2f sfSprite_getScale(const sf::Sprite *sprite) { - sf::Vector2f vec2 = sprite->getScale(); - return {vec2.x, vec2.y}; + return convertVector2(sprite->getScale()); } extern "C" sfVector2f sfSprite_getOrigin(const sf::Sprite *sprite) { - sf::Vector2f vec2 = sprite->getOrigin(); - return {vec2.x, vec2.y}; + return convertVector2(sprite->getOrigin()); } extern "C" void sfSprite_move(sf::Sprite *sprite, sfVector2f offset) { - sprite->move(offset.x, offset.y); + sprite->move(convertVector2(offset)); } extern "C" void sfSprite_rotate(sf::Sprite *sprite, float angle) { - sprite->rotate(angle); + sprite->rotate(sf::degrees(angle)); } extern "C" void sfSprite_scale(sf::Sprite *sprite, sfVector2f factors) { - sprite->scale(factors.x, factors.y); + sprite->scale(convertVector2(factors)); } extern "C" sf::Transform const *sfSprite_getTransform(const sf::Sprite *sprite) { @@ -76,34 +74,30 @@ extern "C" void sfSprite_setTexture(sf::Sprite *sprite, const sf::Texture *textu sprite->setTexture(*texture, resetRect); } -extern "C" void sfSprite_setTextureRect(sf::Sprite *sprite, sfIntRect rectangle) { - sprite->setTextureRect(sf::IntRect(rectangle.left, rectangle.top, rectangle.width, rectangle.height)); +extern "C" void sfSprite_setTextureRect(sf::Sprite *sprite, sfIntRect rect) { + sprite->setTextureRect(convertRect(rect)); } extern "C" void sfSprite_setColor(sf::Sprite *sprite, sfColor color) { - sprite->setColor(sf::Color(color.r, color.g, color.b, color.a)); + sprite->setColor(convertColor(color)); } extern "C" const sf::Texture *sfSprite_getTexture(const sf::Sprite *sprite) { - return sprite->getTexture(); + return &sprite->getTexture(); } extern "C" sfIntRect sfSprite_getTextureRect(const sf::Sprite *sprite) { - sf::IntRect rect = sprite->getTextureRect(); - return {rect.left, rect.top, rect.width, rect.height}; + return convertRect(sprite->getTextureRect()); } extern "C" sfColor sfSprite_getColor(const sf::Sprite *sprite) { - sf::Color color = sprite->getColor(); - return {color.r, color.g, color.b, color.a}; + return convertColor(sprite->getColor()); } extern "C" sfFloatRect sfSprite_getLocalBounds(const sf::Sprite *sprite) { - sf::FloatRect rect = sprite->getLocalBounds(); - return {rect.left, rect.top, rect.width, rect.height}; + return convertRect(sprite->getLocalBounds()); } extern "C" sfFloatRect sfSprite_getGlobalBounds(const sf::Sprite *sprite) { - sf::FloatRect rect = sprite->getGlobalBounds(); - return {rect.left, rect.top, rect.width, rect.height}; + return convertRect(sprite->getGlobalBounds()); } diff --git a/CSFML/src/Graphics/StencilMode.hpp b/CSFML/src/Graphics/StencilMode.hpp new file mode 100644 index 00000000..5dc3d1ae --- /dev/null +++ b/CSFML/src/Graphics/StencilMode.hpp @@ -0,0 +1,92 @@ +#pragma once +#include + +//////////////////////////////////////////////////////// +/// \brief Enumeration of the stencil test comparisons that can be performed +/// +/// The comparisons are mapped directly to their OpenGL equivalents, +/// specified by `glStencilFunc()`. +//////////////////////////////////////////////////////// +typedef enum { + sfStencilComparisonNever, //!< The stencil test never passes + sfStencilComparisonLess, //!< The stencil test passes if the new value is less than the value in the stencil buffer + sfStencilComparisonLessEqual, //!< The stencil test passes if the new value is less than or equal to the value in the stencil buffer + sfStencilComparisonGreater, //!< The stencil test passes if the new value is greater than the value in the stencil buffer + sfStencilComparisonGreaterEqual, //!< The stencil test passes if the new value is greater than or equal to the value in the stencil buffer + sfStencilComparisonEqual, //!< The stencil test passes if the new value is strictly equal to the value in the stencil buffer + sfStencilComparisonNotEqual, //!< The stencil test passes if the new value is strictly unequal to the value in the stencil buffer + sfStencilComparisonAlways //!< The stencil test always passes +} sfStencilComparison; + +//////////////////////////////////////////////////////// +/// \brief Enumeration of the stencil buffer update operations +/// +/// The update operations are mapped directly to their OpenGL equivalents, +/// specified by `glStencilOp()`. +//////////////////////////////////////////////////////// +typedef enum { + sfStencilUpdateOperationKeep, //!< If the stencil test passes, the value in the stencil buffer is not modified + sfStencilUpdateOperationZero, //!< If the stencil test passes, the value in the stencil buffer is set to zero + sfStencilUpdateOperationReplace, //!< If the stencil test passes, the value in the stencil buffer is set to the new value + sfStencilUpdateOperationIncrement, //!< If the stencil test passes, the value in the stencil buffer is incremented and if required clamped + sfStencilUpdateOperationDecrement, //!< If the stencil test passes, the value in the stencil buffer is decremented and if required clamped + sfStencilUpdateOperationInvert, //!< If the stencil test passes, the value in the stencil buffer is bitwise inverted +} sfStencilUpdateOperation; + +//////////////////////////////////////////////////////// +/// \brief Stencil value type (also used as a mask) +/// +//////////////////////////////////////////////////////// +typedef struct +{ + unsigned int value; //!< The stored stencil value +} sfStencilValue; + +//////////////////////////////////////////////////////////// +/// \brief Stencil modes for drawing +/// +//////////////////////////////////////////////////////////// +typedef struct +{ + sfStencilComparison stencilComparison; //!< The comparison we're performing the stencil test with + sfStencilUpdateOperation stencilUpdateOperation; //!< The update operation to perform if the stencil test passes + sfStencilValue stencilReference; //!< The reference value we're performing the stencil test with + sfStencilValue stencilMask; //!< The mask to apply to both the reference value and the value in the stencil buffer + bool stencilOnly; //!< Whether we should update the color buffer in addition to the stencil buffer +} sfStencilMode; + +//////////////////////////////////////////////////////////// +// Convert sf::StencilValue to sfStencilValue +//////////////////////////////////////////////////////////// +[[nodiscard]] inline sfStencilValue convertStencilValue(const sf::StencilValue value) { + return {value.value}; +} + +//////////////////////////////////////////////////////////// +// Convert sfStencilValue to sf::StencilValue +//////////////////////////////////////////////////////////// +[[nodiscard]] inline sf::StencilValue convertStencilValue(const sfStencilValue value) { + return {value.value}; +} + +//////////////////////////////////////////////////////////// +// Convert sf::StencilMode to sfStencilMode +//////////////////////////////////////////////////////////// +[[nodiscard]] inline sfStencilMode convertStencilMode(const sf::StencilMode value) { + return {static_cast(value.stencilComparison), + static_cast(value.stencilUpdateOperation), + convertStencilValue(value.stencilReference), + convertStencilValue(value.stencilMask), + value.stencilOnly}; +} + +//////////////////////////////////////////////////////////// +// Convert sfStencilMode to sf::StencilMode +//////////////////////////////////////////////////////////// +[[nodiscard]] inline sf::StencilMode convertStencilMode(const sfStencilMode value) { + return {static_cast(value.stencilComparison), + static_cast(value.stencilUpdateOperation), + convertStencilValue(value.stencilReference), + convertStencilValue(value.stencilMask), + value.stencilOnly}; +} diff --git a/CSFML/src/Graphics/Text.cpp b/CSFML/src/Graphics/Text.cpp index e44f51ab..3c7f84f8 100644 --- a/CSFML/src/Graphics/Text.cpp +++ b/CSFML/src/Graphics/Text.cpp @@ -1,12 +1,13 @@ #include "Graphics/Color.hpp" #include "Graphics/Rect.hpp" +#include "SFML/Graphics/Font.hpp" #include "System/Vector2.hpp" #include #include #include -extern "C" sf::Text *sfText_new(void) { - return new sf::Text; +extern "C" sf::Text *sfText_new(const sf::Font *font, const uint32_t *string, unsigned int size) { + return new sf::Text(*font, (char32_t *)string, size); } extern "C" sf::Text *sfText_cpy(const sf::Text *text) { @@ -18,50 +19,47 @@ extern "C" void sfText_del(sf::Text *text) { } extern "C" void sfText_setPosition(sf::Text *text, sfVector2f position) { - text->setPosition(position.x, position.y); + text->setPosition(convertVector2(position)); } extern "C" void sfText_setRotation(sf::Text *text, float angle) { - text->setRotation(angle); + text->setRotation(sf::degrees(angle)); } extern "C" void sfText_setScale(sf::Text *text, sfVector2f scale) { - text->setScale(scale.x, scale.y); + text->setScale(convertVector2(scale)); } extern "C" void sfText_setOrigin(sf::Text *text, sfVector2f origin) { - text->setOrigin(origin.x, origin.y); + text->setOrigin(convertVector2(origin)); } extern "C" sfVector2f sfText_getPosition(const sf::Text *text) { - sf::Vector2f vec2 = text->getPosition(); - return {vec2.x, vec2.y}; + return convertVector2(text->getPosition()); } extern "C" float sfText_getRotation(const sf::Text *text) { - return text->getRotation(); + return text->getRotation().asDegrees(); } extern "C" sfVector2f sfText_getScale(const sf::Text *text) { - sf::Vector2f vec2 = text->getScale(); - return {vec2.x, vec2.y}; + return convertVector2(text->getScale()); } extern "C" sfVector2f sfText_getOrigin(const sf::Text *text) { - sf::Vector2f vec2 = text->getOrigin(); - return {vec2.x, vec2.y}; + return convertVector2(text->getOrigin()); } extern "C" void sfText_move(sf::Text *text, sfVector2f offset) { - text->move(offset.x, offset.y); + text->move(convertVector2(offset)); } extern "C" void sfText_rotate(sf::Text *text, float angle) { - text->rotate(angle); + text->rotate(sf::degrees(angle)); } extern "C" void sfText_scale(sf::Text *text, sfVector2f factors) { - text->scale(factors.x, factors.y); + text->scale(convertVector2(factors)); } extern "C" sf::Transform const *sfText_getTransform(const sf::Text *text) { @@ -73,7 +71,7 @@ extern "C" sf::Transform const *sfText_getInverseTransform(const sf::Text *text) } extern "C" void sfText_setUnicodeString(sf::Text *text, const uint32_t *string) { - text->setString(sf::String(string)); + text->setString(sf::String((char32_t *)string)); } extern "C" void sfText_setFont(sf::Text *text, const sf::Font *font) { @@ -97,11 +95,11 @@ extern "C" void sfText_setStyle(sf::Text *text, uint32_t style) { } extern "C" void sfText_setFillColor(sf::Text *text, sfColor color) { - text->setFillColor(sf::Color(color.r, color.g, color.b, color.a)); + text->setFillColor(convertColor(color)); } extern "C" void sfText_setOutlineColor(sf::Text *text, sfColor color) { - text->setOutlineColor(sf::Color(color.r, color.g, color.b, color.a)); + text->setOutlineColor(convertColor(color)); } extern "C" void sfText_setOutlineThickness(sf::Text *text, float thickness) { @@ -109,11 +107,11 @@ extern "C" void sfText_setOutlineThickness(sf::Text *text, float thickness) { } extern "C" const uint32_t *sfText_getUnicodeString(const sf::Text *text) { - return text->getString().getData(); + return (uint32_t *)text->getString().getData(); } extern "C" const sf::Font *sfText_getFont(const sf::Text *text) { - return text->getFont(); + return &text->getFont(); } extern "C" unsigned int sfText_getCharacterSize(const sf::Text *text) { @@ -133,13 +131,11 @@ extern "C" uint32_t sfText_getStyle(const sf::Text *text) { } extern "C" sfColor sfText_getFillColor(const sf::Text *text) { - sf::Color color = text->getFillColor(); - return {color.r, color.g, color.b, color.a}; + return convertColor(text->getFillColor()); } extern "C" sfColor sfText_getOutlineColor(const sf::Text *text) { - sf::Color color = text->getOutlineColor(); - return {color.r, color.g, color.b, color.a}; + return convertColor(text->getOutlineColor()); } extern "C" float sfText_getOutlineThickness(const sf::Text *text) { @@ -147,16 +143,13 @@ extern "C" float sfText_getOutlineThickness(const sf::Text *text) { } extern "C" sfVector2f sfText_findCharacterPos(const sf::Text *text, size_t index) { - sf::Vector2f vec2 = text->findCharacterPos(index); - return {vec2.x, vec2.y}; + return convertVector2(text->findCharacterPos(index)); } extern "C" sfFloatRect sfText_getLocalBounds(const sf::Text *text) { - sf::FloatRect rect = text->getLocalBounds(); - return {rect.left, rect.top, rect.width, rect.height}; + return convertRect(text->getLocalBounds()); } extern "C" sfFloatRect sfText_getGlobalBounds(const sf::Text *text) { - sf::FloatRect rect = text->getGlobalBounds(); - return {rect.left, rect.top, rect.width, rect.height}; + return convertRect(text->getGlobalBounds()); } diff --git a/CSFML/src/Graphics/Texture.cpp b/CSFML/src/Graphics/Texture.cpp index 7f8a9a80..fd727cf7 100644 --- a/CSFML/src/Graphics/Texture.cpp +++ b/CSFML/src/Graphics/Texture.cpp @@ -1,4 +1,5 @@ #include "Graphics/Rect.hpp" +#include "SFML/Graphics/Image.hpp" #include "System/InputStreamHelper.hpp" #include "System/Vector2.hpp" #include @@ -17,53 +18,52 @@ extern "C" void sfTexture_del(sf::Texture *texture) { delete texture; } -extern "C" bool sfTexture_create(sf::Texture *tex, unsigned int width, unsigned int height) { - return tex->create(width, height); +extern "C" bool sfTexture_resize(sf::Texture *texture, sfVector2u size, bool sRgb) { + return texture->resize(convertVector2(size), sRgb); } -extern "C" bool sfTexture_loadFromFile(sf::Texture *tex, const char *filename, const sfIntRect area) { - return tex->loadFromFile(filename, sf::IntRect(area.left, area.top, area.width, area.height)); +extern "C" bool sfTexture_loadFromFile(sf::Texture *tex, const char *filename, bool sRgb, const sfIntRect area) { + return tex->loadFromFile(filename, sRgb, convertRect(area)); } -extern "C" bool sfTexture_loadFromMemory(sf::Texture *tex, const void *data, size_t sizeInBytes, const sfIntRect area) { - return tex->loadFromMemory(data, sizeInBytes, sf::IntRect(area.left, area.top, area.width, area.height)); +extern "C" bool sfTexture_loadFromMemory(sf::Texture *tex, const void *data, size_t sizeInBytes, bool sRgb, const sfIntRect area) { + return tex->loadFromMemory(data, sizeInBytes, sRgb, convertRect(area)); } -extern "C" bool sfTexture_loadFromStream(sf::Texture *tex, sfInputStreamHelper *stream, const sfIntRect area) { - return tex->loadFromStream(*stream, sf::IntRect(area.left, area.top, area.width, area.height)); +extern "C" bool sfTexture_loadFromStream(sf::Texture *tex, sfInputStreamHelper *stream, bool sRgb, const sfIntRect area) { + return tex->loadFromStream(*stream, sRgb, convertRect(area)); } -extern "C" bool sfTexture_loadFromImage(sf::Texture *tex, const sf::Image *image, const sfIntRect area) { - return tex->loadFromImage(*image, sf::IntRect(area.left, area.top, area.width, area.height)); +extern "C" bool sfTexture_loadFromImage(sf::Texture *tex, const sf::Image *image, bool sRgb, const sfIntRect area) { + return tex->loadFromImage(*image, sRgb, convertRect(area)); } extern "C" sfVector2u sfTexture_getSize(const sf::Texture *texture) { - sf::Vector2u vec2 = texture->getSize(); - return {vec2.x, vec2.y}; + return convertVector2(texture->getSize()); } extern "C" sf::Image *sfTexture_copyToImage(const sf::Texture *texture) { return new sf::Image(texture->copyToImage()); } -extern "C" void sfTexture_updateFromPixels(sf::Texture *texture, const uint8_t *pixels, unsigned int width, unsigned int height, unsigned int x, unsigned int y) { - texture->update(pixels, width, height, x, y); +extern "C" void sfTexture_updateFromPixels(sf::Texture *texture, const uint8_t *pixels, sfVector2u size, sfVector2u dest) { + texture->update(pixels, convertVector2(size), convertVector2(dest)); } -extern "C" void sfTexture_updateFromTexture(sf::Texture *destination, const sf::Texture *texture, unsigned int x, unsigned int y) { - destination->update(*texture, x, y); +extern "C" void sfTexture_updateFromTexture(sf::Texture *destination, const sf::Texture *texture, sfVector2u dest) { + destination->update(*texture, convertVector2(dest)); } -extern "C" void sfTexture_updateFromImage(sf::Texture *texture, const sf::Image *image, unsigned int x, unsigned int y) { - texture->update(*image, x, y); +extern "C" void sfTexture_updateFromImage(sf::Texture *texture, const sf::Image *image, sfVector2u dest) { + texture->update(*image, convertVector2(dest)); } -extern "C" void sfTexture_updateFromWindow(sf::Texture *texture, const sf::Window *window, unsigned int x, unsigned int y) { - texture->update(*window, x, y); +extern "C" void sfTexture_updateFromWindow(sf::Texture *texture, const sf::Window *window, sfVector2u dest) { + texture->update(*window, convertVector2(dest)); } -extern "C" void sfTexture_updateFromRenderWindow(sf::Texture *texture, const sf::RenderWindow *renderWindow, unsigned int x, unsigned int y) { - texture->update(*renderWindow, x, y); +extern "C" void sfTexture_updateFromRenderWindow(sf::Texture *texture, const sf::RenderWindow *renderWindow, sfVector2u dest) { + texture->update(*renderWindow, convertVector2(dest)); } extern "C" void sfTexture_setSmooth(sf::Texture *texture, bool smooth) { @@ -74,10 +74,6 @@ extern "C" bool sfTexture_isSmooth(const sf::Texture *texture) { return texture->isSmooth(); } -extern "C" void sfTexture_setSrgb(sf::Texture *texture, bool sRgb) { - texture->setSrgb(sRgb); -} - extern "C" bool sfTexture_isSrgb(const sf::Texture *texture) { return texture->isSrgb(); } @@ -87,7 +83,6 @@ extern "C" void sfTexture_setRepeated(sf::Texture *texture, bool repeated) { } extern "C" bool sfTexture_isRepeated(const sf::Texture *texture) { - return texture->isRepeated(); } diff --git a/CSFML/src/Graphics/Transform.cpp b/CSFML/src/Graphics/Transform.cpp index bb6fcfc7..ed7f9d96 100644 --- a/CSFML/src/Graphics/Transform.cpp +++ b/CSFML/src/Graphics/Transform.cpp @@ -1,38 +1,35 @@ #include "Graphics/Rect.hpp" #include "System/Vector2.hpp" #include -#include extern "C" sfVector2f sfTransform_transformPoint(const sf::Transform *transform, sfVector2f point) { - sf::Vector2f vec2 = transform->transformPoint(point.x, point.y); - return {vec2.x, vec2.y}; + return convertVector2(transform->transformPoint(convertVector2(point))); } extern "C" sfFloatRect sfTransform_transformRect(const sf::Transform *transform, sfFloatRect rectangle) { - sf::FloatRect rect = transform->transformRect(sf::FloatRect(rectangle.left, rectangle.top, rectangle.width, rectangle.height)); - return {rect.left, rect.top, rect.width, rect.height}; + return convertRect(transform->transformRect(convertRect(rectangle))); } extern "C" void sfTransform_combine(sf::Transform *transform, const sf::Transform *other) { transform->combine(*other); } -extern "C" void sfTransform_translate(sf::Transform *transform, float x, float y) { - transform->translate(x, y); +extern "C" void sfTransform_translate(sf::Transform *transform, sfVector2f offset) { + transform->translate(convertVector2(offset)); } extern "C" void sfTransform_rotate(sf::Transform *transform, float angle) { - transform->rotate(angle); + transform->rotate(sf::degrees(angle)); } -extern "C" void sfTransform_rotateWithCenter(sf::Transform *transform, float angle, float centerX, float centerY) { - transform->rotate(angle, centerX, centerY); +extern "C" void sfTransform_rotateWithCenter(sf::Transform *transform, float angle, sfVector2f center) { + transform->rotate(sf::degrees(angle), convertVector2(center)); } -extern "C" void sfTransform_scale(sf::Transform *transform, float scaleX, float scaleY) { - transform->scale(scaleX, scaleY); +extern "C" void sfTransform_scale(sf::Transform *transform, sfVector2f scale) { + transform->scale(convertVector2(scale)); } -extern "C" void sfTransform_scaleWithCenter(sf::Transform *transform, float scaleX, float scaleY, float centerX, float centerY) { - transform->scale(scaleX, scaleY, centerX, centerY); +extern "C" void sfTransform_scaleWithCenter(sf::Transform *transform, sfVector2f scale, sfVector2f center) { + transform->scale(convertVector2(scale), convertVector2(center)); } diff --git a/CSFML/src/Graphics/Transform.hpp b/CSFML/src/Graphics/Transform.hpp new file mode 100644 index 00000000..c5451e70 --- /dev/null +++ b/CSFML/src/Graphics/Transform.hpp @@ -0,0 +1,30 @@ +//////////////////////////////////////////////////////////// +/// \brief Encapsulate a 3x3 transform matrix +/// +//////////////////////////////////////////////////////////// +#include +typedef struct +{ + float matrix[9]; +} sfTransform; + +//////////////////////////////////////////////////////////// +// Convert sf::Transform to sfTransform +//////////////////////////////////////////////////////////// +[[nodiscard]] inline sfTransform convertTransform(const sf::Transform &transform) { + const float *m = transform.getMatrix(); + return {m[0], m[4], m[12], m[1], m[5], m[13], m[3], m[7], m[15]}; +} + +//////////////////////////////////////////////////////////// +// Convert sfTransform to sf::Transform +//////////////////////////////////////////////////////////// +[[nodiscard]] inline sf::Transform convertTransform(const sfTransform &transform) { + const float *m = transform.matrix; + + // clang-format off + return {m[0], m[1], m[2], + m[3], m[4], m[5], + m[6], m[7], m[8]}; + // clang-format on +} diff --git a/CSFML/src/Graphics/VertexBuffer.cpp b/CSFML/src/Graphics/VertexBuffer.cpp index ad3579d6..3ab3234d 100644 --- a/CSFML/src/Graphics/VertexBuffer.cpp +++ b/CSFML/src/Graphics/VertexBuffer.cpp @@ -1,3 +1,5 @@ +#include "Graphics/PrimitiveType.hpp" +#include "SFML/Graphics/PrimitiveType.hpp" #include "SFML/Graphics/RenderTarget.hpp" #include #include @@ -38,12 +40,12 @@ extern "C" unsigned int sfVertexBuffer_getNativeHandle(const sf::VertexBuffer *v return vertexBuffer->getNativeHandle(); } -extern "C" void sfVertexBuffer_setPrimitiveType(sf::VertexBuffer *vertexBuffer, sf::PrimitiveType type) { - vertexBuffer->setPrimitiveType(type); +extern "C" void sfVertexBuffer_setPrimitiveType(sf::VertexBuffer *vertexBuffer, sfPrimitiveType type) { + vertexBuffer->setPrimitiveType(static_cast(type)); } -extern "C" sf::PrimitiveType sfVertexBuffer_getPrimitiveType(const sf::VertexBuffer *vertexBuffer) { - return vertexBuffer->getPrimitiveType(); +extern "C" sfPrimitiveType sfVertexBuffer_getPrimitiveType(const sf::VertexBuffer *vertexBuffer) { + return static_cast(vertexBuffer->getPrimitiveType()); } extern "C" void sfVertexBuffer_setUsage(sf::VertexBuffer *vertexBuffer, sf::VertexBuffer::Usage usage) { diff --git a/CSFML/src/Graphics/View.cpp b/CSFML/src/Graphics/View.cpp index e0cebfb9..8b214788 100644 --- a/CSFML/src/Graphics/View.cpp +++ b/CSFML/src/Graphics/View.cpp @@ -15,50 +15,51 @@ extern "C" sf::View *sfView_cpy(const sf::View *view) { } extern "C" void sfView_setCenter(sf::View *view, sfVector2f center) { - view->setCenter(center.x, center.y); + view->setCenter(convertVector2(center)); } extern "C" void sfView_setSize(sf::View *view, sfVector2f size) { - view->setSize(size.x, size.y); + view->setSize(convertVector2(size)); } extern "C" void sfView_setRotation(sf::View *view, float angle) { - view->setRotation(angle); + view->setRotation(sf::degrees(angle)); } extern "C" void sfView_setViewport(sf::View *view, sfFloatRect viewport) { - view->setViewport(sf::FloatRect(viewport.left, viewport.top, viewport.width, viewport.height)); + view->setViewport(convertRect(viewport)); } -extern "C" void sfView_reset(sf::View *view, sfFloatRect rectangle) { - view->reset(sf::FloatRect(rectangle.left, rectangle.top, rectangle.width, rectangle.height)); +extern "C" void sfView_setScissor(sf::View *view, sfFloatRect scissor) { + view->setScissor(convertRect(scissor)); } extern "C" sfVector2f sfView_getCenter(const sf::View *view) { - sf::Vector2f vec2 = view->getCenter(); - return {vec2.x, vec2.y}; + return convertVector2(view->getCenter()); } extern "C" sfVector2f sfView_getSize(const sf::View *view) { - sf::Vector2f vec2 = view->getSize(); - return {vec2.x, vec2.y}; + return convertVector2(view->getSize()); } extern "C" float sfView_getRotation(const sf::View *view) { - return view->getRotation(); + return view->getRotation().asDegrees(); } extern "C" sfFloatRect sfView_getViewport(const sf::View *view) { - sf::FloatRect rect = view->getViewport(); - return {rect.left, rect.top, rect.width, rect.height}; + return convertRect(view->getViewport()); +} + +extern "C" sfFloatRect sfView_getScissor(const sf::View *view) { + return convertRect(view->getScissor()); } extern "C" void sfView_move(sf::View *view, sfVector2f offset) { - view->move(offset.x, offset.y); + view->move(convertVector2(offset)); } extern "C" void sfView_rotate(sf::View *view, float angle) { - view->rotate(angle); + view->rotate(sf::degrees(angle)); } extern "C" void sfView_zoom(sf::View *view, float factor) { diff --git a/CSFML/src/System/Buffer.cpp b/CSFML/src/System/Buffer.cpp new file mode 100644 index 00000000..33c7792e --- /dev/null +++ b/CSFML/src/System/Buffer.cpp @@ -0,0 +1,15 @@ +#include "System/Buffer.hpp" +#include +#include + +extern "C" void sfBuffer_destroy(sfBuffer *buffer) { + delete buffer; +} + +extern "C" const uint8_t *sfBuffer_getData(const sfBuffer *buffer) { + return buffer->data(); +} + +extern "C" std::size_t sfBuffer_getSize(const sfBuffer *buffer) { + return buffer->size(); +} diff --git a/CSFML/src/System/Buffer.hpp b/CSFML/src/System/Buffer.hpp new file mode 100644 index 00000000..03d435b8 --- /dev/null +++ b/CSFML/src/System/Buffer.hpp @@ -0,0 +1,7 @@ +#pragma once + +#include +#include + +struct sfBuffer : std::vector { +}; diff --git a/CSFML/src/System/Clock.cpp b/CSFML/src/System/Clock.cpp index 13c69b2d..9f1059e7 100644 --- a/CSFML/src/System/Clock.cpp +++ b/CSFML/src/System/Clock.cpp @@ -1,3 +1,4 @@ +#include #include extern "C" sf::Clock *sfClock_new(void) { @@ -8,10 +9,26 @@ extern "C" void sfClock_delete(sf::Clock *clock) { delete clock; } -extern "C" sf::Int64 sfClock_getElapsedTime(const sf::Clock *clock) { +extern "C" int64_t sfClock_getElapsedTime(const sf::Clock *clock) { return clock->getElapsedTime().asMicroseconds(); } -extern "C" sf::Int64 sfClock_restart(sf::Clock *clock) { +extern "C" bool sfClock_isRunning(const sf::Clock *clock) { + return clock->isRunning(); +} + +extern "C" void sfClock_start(sf::Clock *clock) { + clock->start(); +} + +extern "C" void sfClock_stop(sf::Clock *clock) { + clock->stop(); +} + +extern "C" int64_t sfClock_restart(sf::Clock *clock) { return clock->restart().asMicroseconds(); } + +extern "C" int64_t sfClock_reset(sf::Clock *clock) { + return clock->reset().asMicroseconds(); +} diff --git a/CSFML/src/System/InputStreamHelper.hpp b/CSFML/src/System/InputStreamHelper.hpp index 95532328..71ebb88e 100644 --- a/CSFML/src/System/InputStreamHelper.hpp +++ b/CSFML/src/System/InputStreamHelper.hpp @@ -4,8 +4,8 @@ #include #include -typedef int64_t (*sfInputStreamHelperReadCb)(void *data, int64_t size, void *userData); -typedef int64_t (*sfInputStreamHelperSeekCb)(int64_t position, void *userData); +typedef int64_t (*sfInputStreamHelperReadCb)(void *data, size_t size, void *userData); +typedef int64_t (*sfInputStreamHelperSeekCb)(size_t position, void *userData); typedef int64_t (*sfInputStreamHelperTellCb)(void *userData); typedef int64_t (*sfInputStreamHelperGetSizeCb)(void *userData); @@ -14,19 +14,19 @@ struct sfInputStreamHelper final : public sf::InputStream { sfInputStreamHelperSeekCb seek, sfInputStreamHelperTellCb tell, sfInputStreamHelperGetSizeCb getSize, void *userData); - virtual sf::Int64 read(void *data, sf::Int64 size) final { + virtual std::optional read(void *data, std::size_t size) final { return readCb(data, size, userData); } - virtual sf::Int64 seek(sf::Int64 position) final { + virtual std::optional seek(std::size_t position) final { return seekCb(position, userData); } - virtual sf::Int64 tell() final { + virtual std::optional tell() final { return tellCb(userData); } - virtual sf::Int64 getSize() final { + virtual std::optional getSize() final { return getSizeCb(userData); } sfInputStreamHelperReadCb readCb; diff --git a/CSFML/src/System/SfString.cpp b/CSFML/src/System/SfString.cpp index 037d56f9..521d1aad 100644 --- a/CSFML/src/System/SfString.cpp +++ b/CSFML/src/System/SfString.cpp @@ -4,8 +4,8 @@ extern "C" std::size_t sfString_getLength(const sf::String *string) { return string->getSize(); } -extern "C" const sf::Uint32 *sfString_getData(const sf::String *string) { - return string->getData(); +extern "C" const uint32_t *sfString_getData(const sf::String *string) { + return (uint32_t *)string->getData(); } extern "C" void sfString_delete(sf::String *string) { diff --git a/CSFML/src/System/Sleep.cpp b/CSFML/src/System/Sleep.cpp index eec702fc..cc775be7 100644 --- a/CSFML/src/System/Sleep.cpp +++ b/CSFML/src/System/Sleep.cpp @@ -1,5 +1,7 @@ +#include #include +#include -extern "C" void sfSleep(sf::Int64 duration_ms) { +extern "C" void sfSleep(int64_t duration_ms) { sf::sleep(sf::microseconds(duration_ms)); } diff --git a/CSFML/src/System/Vector2.hpp b/CSFML/src/System/Vector2.hpp index c634c8fe..fdf3276e 100644 --- a/CSFML/src/System/Vector2.hpp +++ b/CSFML/src/System/Vector2.hpp @@ -1,6 +1,6 @@ -#ifndef SFML_VECTOR2_H -#define SFML_VECTOR2_H +#pragma once +#include "SFML/System/Vector2.hpp" struct sfVector2i { int x; int y; @@ -16,4 +16,28 @@ struct sfVector2f { float y; }; -#endif // SFML_VECTOR2_H +//////////////////////////////////////////////////////////// +// Convert sf::Vector2 to sfVector2 +//////////////////////////////////////////////////////////// +[[nodiscard]] inline sfVector2i convertVector2(const sf::Vector2i vector) { + return {vector.x, vector.y}; +} +[[nodiscard]] inline sfVector2u convertVector2(const sf::Vector2u vector) { + return {vector.x, vector.y}; +} +[[nodiscard]] inline sfVector2f convertVector2(const sf::Vector2f vector) { + return {vector.x, vector.y}; +} + +//////////////////////////////////////////////////////////// +// Convert sfVector2 to sf::Vector2 +//////////////////////////////////////////////////////////// +[[nodiscard]] inline sf::Vector2i convertVector2(const sfVector2i vector) { + return {vector.x, vector.y}; +} +[[nodiscard]] inline sf::Vector2u convertVector2(const sfVector2u vector) { + return {vector.x, vector.y}; +} +[[nodiscard]] inline sf::Vector2f convertVector2(const sfVector2f vector) { + return {vector.x, vector.y}; +} diff --git a/CSFML/src/System/Vector3.hpp b/CSFML/src/System/Vector3.hpp index 3acef6a4..71fa20e9 100644 --- a/CSFML/src/System/Vector3.hpp +++ b/CSFML/src/System/Vector3.hpp @@ -1,10 +1,22 @@ -#ifndef SFML_VECTOR3_H -#define SFML_VECTOR3_H +#pragma once +#include "SFML/System/Vector3.hpp" struct sfVector3f { float x; float y; float z; }; -#endif // SFML_VECTOR3_H +//////////////////////////////////////////////////////////// +// Convert sf::Vector3f to sfVector3f +//////////////////////////////////////////////////////////// +[[nodiscard]] inline sfVector3f convertVector3(const sf::Vector3f vector) { + return {vector.x, vector.y, vector.z}; +} + +//////////////////////////////////////////////////////////// +// Convert sfVector3f to sf::Vector3f +//////////////////////////////////////////////////////////// +[[nodiscard]] inline sf::Vector3f convertVector3(const sfVector3f vector) { + return {vector.x, vector.y, vector.z}; +} diff --git a/CSFML/src/Window/Clipboard.cpp b/CSFML/src/Window/Clipboard.cpp index 00b231ab..8d83417e 100644 --- a/CSFML/src/Window/Clipboard.cpp +++ b/CSFML/src/Window/Clipboard.cpp @@ -1,10 +1,10 @@ +#include #include -#include extern "C" sf::String *sfClipboard_getUnicodeString() { return new sf::String(sf::Clipboard::getString()); } extern "C" void sfClipboard_setUnicodeString(const uint32_t *text) { - sf::Clipboard::setString(text); + sf::Clipboard::setString((char32_t *)text); } diff --git a/CSFML/src/Window/Context.cpp b/CSFML/src/Window/Context.cpp index 8158776f..b98fa99f 100644 --- a/CSFML/src/Window/Context.cpp +++ b/CSFML/src/Window/Context.cpp @@ -9,6 +9,10 @@ extern "C" void sfContext_del(sf::Context *context) { delete context; } +extern "C" bool sfContext_isExtensionAvailable(const char *name) { + return sf::Context::isExtensionAvailable(name); +} + extern "C" bool sfContext_setActive(sf::Context *context, bool active) { return context->setActive(active); } @@ -27,4 +31,4 @@ extern "C" const sf::Context *sfContext_getActiveContext() { extern "C" sf::GlFunctionPointer sfContext_getFunction(const char *name) { return sf::Context::getFunction(name); -} \ No newline at end of file +} diff --git a/CSFML/src/Window/Cursor.cpp b/CSFML/src/Window/Cursor.cpp index eda627cb..fd99c664 100644 --- a/CSFML/src/Window/Cursor.cpp +++ b/CSFML/src/Window/Cursor.cpp @@ -1,19 +1,23 @@ +#include "Window/Cursor.hpp" #include "System/Vector2.hpp" #include -#include -extern "C" sf::Cursor *sfCursor_new() { - return new sf::Cursor; -} +extern "C" sf::Cursor *sfCursor_createFromPixels(const uint8_t *pixels, sfVector2u size, sfVector2u hotspot) { + auto cursor = sf::Cursor::createFromPixels(pixels, {size.x, size.y}, {hotspot.x, hotspot.y}); + if (!cursor) + return nullptr; -extern "C" void sfCursor_del(sf::Cursor *cursor) { - delete cursor; + return new sf::Cursor{std::move(*cursor)}; } -extern "C" bool sfCursor_loadFromPixels(sf::Cursor *cursor, const uint8_t *pixels, sfVector2u size, sfVector2u hotspot) { - return cursor->loadFromPixels(pixels, sf::Vector2u(size.x, size.y), sf::Vector2u(hotspot.x, hotspot.y)); +extern "C" sf::Cursor *sfCursor_createFromSystem(sfCursorType type) { + auto cursor = sf::Cursor::createFromSystem(static_cast(type)); + if (!cursor) + return nullptr; + + return new sf::Cursor{std::move(*cursor)}; } -extern "C" bool sfCursor_loadFromSystem(sf::Cursor *cursor, sf::Cursor::Type type) { - return cursor->loadFromSystem(type); +extern "C" void sfCursor_del(sf::Cursor *cursor) { + delete cursor; } diff --git a/CSFML/src/Window/Cursor.hpp b/CSFML/src/Window/Cursor.hpp new file mode 100644 index 00000000..b1988e28 --- /dev/null +++ b/CSFML/src/Window/Cursor.hpp @@ -0,0 +1,24 @@ +#pragma once +enum sfCursorType { + Arrow, //!< Arrow cursor (default) + ArrowWait, //!< Busy arrow cursor + Wait, //!< Busy cursor + Text, //!< I-beam, cursor when hovering over a field allowing text entry + Hand, //!< Pointing hand cursor + SizeHorizontal, //!< Horizontal double arrow cursor + SizeVertical, //!< Vertical double arrow cursor + SizeTopLeftBottomRight, //!< Double arrow cursor going from top-left to bottom-right + SizeBottomLeftTopRight, //!< Double arrow cursor going from bottom-left to top-right + SizeLeft, //!< Left arrow cursor on Linux, same as SizeHorizontal on other platforms + SizeRight, //!< Right arrow cursor on Linux, same as SizeHorizontal on other platforms + SizeTop, //!< Up arrow cursor on Linux, same as SizeVertical on other platforms + SizeBottom, //!< Down arrow cursor on Linux, same as SizeVertical on other platforms + SizeTopLeft, //!< Top-left arrow cursor on Linux, same as SizeTopLeftBottomRight on other platforms + SizeBottomRight, //!< Bottom-right arrow cursor on Linux, same as SizeTopLeftBottomRight on other platforms + SizeBottomLeft, //!< Bottom-left arrow cursor on Linux, same as SizeBottomLeftTopRight on other platforms + SizeTopRight, //!< Top-right arrow cursor on Linux, same as SizeBottomLeftTopRight on other platforms + SizeAll, //!< Combination of SizeHorizontal and SizeVertical + Cross, //!< Crosshair cursor + Help, //!< Help cursor + NotAllowed //!< Action not allowed cursor +}; diff --git a/CSFML/src/Window/Event.hpp b/CSFML/src/Window/Event.hpp new file mode 100644 index 00000000..03a410f3 --- /dev/null +++ b/CSFML/src/Window/Event.hpp @@ -0,0 +1,291 @@ +#pragma once + +#include "System/Vector2.hpp" +#include "System/Vector3.hpp" +#include "Window/Joystick.hpp" +#include "Window/Keyboard.hpp" +#include "Window/Mouse.hpp" +#include "Window/Sensor.hpp" +#include +#include +#include + +//////////////////////////////////////////////////////////// +/// \brief Definition of all the event types +/// +//////////////////////////////////////////////////////////// +typedef enum { + sfEvtClosed, ///< The window requested to be closed (no data) + sfEvtResized, ///< The window was resized (data in event.size) + sfEvtFocusLost, ///< The window lost the focus (no data) + sfEvtFocusGained, ///< The window gained the focus (no data) + sfEvtTextEntered, ///< A character was entered (data in event.text) + sfEvtKeyPressed, ///< A key was pressed (data in event.key) + sfEvtKeyReleased, ///< A key was released (data in event.key) + sfEvtMouseWheelScrolled, ///< The mouse wheel was scrolled (data in event.mouseWheelScroll) + sfEvtMouseButtonPressed, ///< A mouse button was pressed (data in event.mouseButton) + sfEvtMouseButtonReleased, ///< A mouse button was released (data in event.mouseButton) + sfEvtMouseMoved, ///< The mouse cursor moved (data in event.mouseMove) + sfEvtMouseMovedRaw, ///< The mouse cursor moved (data in event.mouseMove) + sfEvtMouseEntered, ///< The mouse cursor entered the area of the window (no data) + sfEvtMouseLeft, ///< The mouse cursor left the area of the window (no data) + sfEvtJoystickButtonPressed, ///< A joystick button was pressed (data in event.joystickButton) + sfEvtJoystickButtonReleased, ///< A joystick button was released (data in event.joystickButton) + sfEvtJoystickMoved, ///< The joystick moved along an axis (data in event.joystickMove) + sfEvtJoystickConnected, ///< A joystick was connected (data in event.joystickConnect) + sfEvtJoystickDisconnected, ///< A joystick was disconnected (data in event.joystickConnect) + sfEvtTouchBegan, ///< A touch event began (data in event.touch) + sfEvtTouchMoved, ///< A touch moved (data in event.touch) + sfEvtTouchEnded, ///< A touch event ended (data in event.touch) + sfEvtSensorChanged, ///< A sensor value changed (data in event.sensor) + + sfEvtCount ///< Keep last -- the total number of event types +} sfEventType; + +//////////////////////////////////////////////////////////// +/// \brief Keyboard event parameters +/// +//////////////////////////////////////////////////////////// +typedef struct +{ + sfEventType type; + sfKeyCode code; + sfScancode scancode; + bool alt; + bool control; + bool shift; + bool system; +} sfKeyEvent; + +//////////////////////////////////////////////////////////// +/// \brief Text event parameters +/// +//////////////////////////////////////////////////////////// +typedef struct +{ + sfEventType type; + uint32_t unicode; +} sfTextEvent; + +//////////////////////////////////////////////////////////// +/// \brief Mouse move event parameters +/// +//////////////////////////////////////////////////////////// +typedef struct +{ + sfEventType type; + sfVector2i position; +} sfMouseMoveEvent; + +//////////////////////////////////////////////////////////// +/// \brief Mouse move raw event parameters +/// +//////////////////////////////////////////////////////////// +typedef struct +{ + sfEventType type; + sfVector2i delta; +} sfMouseMoveRawEvent; + +//////////////////////////////////////////////////////////// +/// \brief Mouse buttons events parameters +/// +//////////////////////////////////////////////////////////// +typedef struct +{ + sfEventType type; + sfMouseButton button; + sfVector2i position; +} sfMouseButtonEvent; + +//////////////////////////////////////////////////////////// +/// \brief Mouse wheel events parameters +/// +//////////////////////////////////////////////////////////// +typedef struct +{ + sfEventType type; + sfMouseWheel wheel; + float delta; + sfVector2i position; +} sfMouseWheelScrollEvent; + +//////////////////////////////////////////////////////////// +/// \brief Joystick axis move event parameters +/// +//////////////////////////////////////////////////////////// +typedef struct +{ + sfEventType type; + unsigned int joystickId; + sfJoystickAxis axis; + float position; +} sfJoystickMoveEvent; + +//////////////////////////////////////////////////////////// +/// \brief Joystick buttons events parameters +/// +//////////////////////////////////////////////////////////// +typedef struct +{ + sfEventType type; + unsigned int joystickId; + unsigned int button; +} sfJoystickButtonEvent; + +//////////////////////////////////////////////////////////// +/// \brief Joystick connection/disconnection event parameters +/// +//////////////////////////////////////////////////////////// +typedef struct +{ + sfEventType type; + unsigned int joystickId; +} sfJoystickConnectEvent; + +//////////////////////////////////////////////////////////// +/// \brief Size events parameters +/// +//////////////////////////////////////////////////////////// +typedef struct +{ + sfEventType type; + sfVector2u size; +} sfSizeEvent; + +//////////////////////////////////////////////////////////// +/// \brief Touch events parameters +/// +//////////////////////////////////////////////////////////// +typedef struct +{ + sfEventType type; + unsigned int finger; + sfVector2i position; +} sfTouchEvent; + +//////////////////////////////////////////////////////////// +/// \brief Sensor event parameters +/// +//////////////////////////////////////////////////////////// +typedef struct +{ + sfEventType type; + sfSensorType sensorType; + sfVector3f value; +} sfSensorEvent; + +//////////////////////////////////////////////////////////// +/// \brief sfEvent defines a system event and its parameters +/// +//////////////////////////////////////////////////////////// +typedef union { + sfEventType type; ///< Type of the event + sfSizeEvent size; ///< Size event parameters + sfKeyEvent key; ///< Key event parameters + sfTextEvent text; ///< Text event parameters + sfMouseMoveEvent mouseMove; ///< Mouse move event parameters + sfMouseMoveRawEvent mouseMoveRaw; ///< Mouse move raw event parameters + sfMouseButtonEvent mouseButton; ///< Mouse button event parameters + sfMouseWheelScrollEvent mouseWheelScroll; ///< Mouse wheel event parameters + sfJoystickMoveEvent joystickMove; ///< Joystick move event parameters + sfJoystickButtonEvent joystickButton; ///< Joystick button event parameters + sfJoystickConnectEvent joystickConnect; ///< Joystick (dis)connect event parameters + sfTouchEvent touch; ///< Touch events parameters + sfSensorEvent sensor; ///< Sensor event parameters +} sfEvent; + +[[nodiscard]] inline bool convertEvent(const std::optional &sfmlEvent, sfEvent &event) { + if (!sfmlEvent) + return false; + + if (sfmlEvent->is()) { + event.type = sfEvtClosed; + } else if (const auto *resized = sfmlEvent->getIf()) { + event.type = sfEvtResized; + event.size.size = {resized->size.x, resized->size.y}; + } else if (sfmlEvent->is()) { + event.type = sfEvtFocusLost; + } else if (sfmlEvent->is()) { + event.type = sfEvtFocusGained; + } else if (const auto *textEntered = sfmlEvent->getIf()) { + event.type = sfEvtTextEntered; + event.text.unicode = textEntered->unicode; + } else if (const auto *keyReleased = sfmlEvent->getIf()) { + event.type = sfEvtKeyReleased; + event.key.code = static_cast(keyReleased->code); + event.key.scancode = static_cast(keyReleased->scancode); + event.key.alt = keyReleased->alt; + event.key.control = keyReleased->control; + event.key.shift = keyReleased->shift; + event.key.system = keyReleased->system; + } else if (const auto *keyPressed = sfmlEvent->getIf()) { + event.type = sfEvtKeyPressed; + event.key.code = static_cast(keyPressed->code); + event.key.scancode = static_cast(keyPressed->scancode); + event.key.alt = keyPressed->alt; + event.key.control = keyPressed->control; + event.key.shift = keyPressed->shift; + event.key.system = keyPressed->system; + } else if (const auto *mouseWheelScrolled = sfmlEvent->getIf()) { + event.type = sfEvtMouseWheelScrolled; + event.mouseWheelScroll.wheel = static_cast(mouseWheelScrolled->wheel); + event.mouseWheelScroll.delta = mouseWheelScrolled->delta; + event.mouseWheelScroll.position = {mouseWheelScrolled->position.x, mouseWheelScrolled->position.y}; + } else if (const auto *mouseButtonPressed = sfmlEvent->getIf()) { + event.type = sfEvtMouseButtonPressed; + event.mouseButton.button = static_cast(mouseButtonPressed->button); + event.mouseButton.position = {mouseButtonPressed->position.x, mouseButtonPressed->position.y}; + } else if (const auto *mouseButtonReleased = sfmlEvent->getIf()) { + event.type = sfEvtMouseButtonReleased; + event.mouseButton.button = static_cast(mouseButtonReleased->button); + event.mouseButton.position = {mouseButtonReleased->position.x, mouseButtonReleased->position.y}; + } else if (const auto *mouseMoved = sfmlEvent->getIf()) { + event.type = sfEvtMouseMoved; + event.mouseMove.position = {mouseMoved->position.x, mouseMoved->position.y}; + } else if (const auto *mouseMovedRaw = sfmlEvent->getIf()) { + event.type = sfEvtMouseMovedRaw; + event.mouseMoveRaw.delta = {mouseMovedRaw->delta.x, mouseMovedRaw->delta.y}; + } else if (sfmlEvent->is()) { + event.type = sfEvtMouseEntered; + } else if (sfmlEvent->is()) { + event.type = sfEvtMouseLeft; + } else if (const auto *joystickButtonPressed = sfmlEvent->getIf()) { + event.type = sfEvtJoystickButtonPressed; + event.joystickButton.joystickId = joystickButtonPressed->joystickId; + event.joystickButton.button = joystickButtonPressed->button; + } else if (const auto *joystickButtonReleased = sfmlEvent->getIf()) { + event.type = sfEvtJoystickButtonReleased; + event.joystickButton.joystickId = joystickButtonReleased->joystickId; + event.joystickButton.button = joystickButtonReleased->button; + } else if (const auto *joystickMoved = sfmlEvent->getIf()) { + event.type = sfEvtJoystickMoved; + event.joystickMove.joystickId = joystickMoved->joystickId; + event.joystickMove.axis = static_cast(joystickMoved->axis); + event.joystickMove.position = joystickMoved->position; + } else if (const auto *joystickConnected = sfmlEvent->getIf()) { + event.type = sfEvtJoystickConnected; + event.joystickConnect.joystickId = joystickConnected->joystickId; + } else if (const auto *joystickDisconnected = sfmlEvent->getIf()) { + event.type = sfEvtJoystickDisconnected; + event.joystickConnect.joystickId = joystickDisconnected->joystickId; + } else if (const auto *touchBegan = sfmlEvent->getIf()) { + event.type = sfEvtTouchBegan; + event.touch.finger = touchBegan->finger; + event.touch.position = {touchBegan->position.x, touchBegan->position.y}; + } else if (const auto *touchMoved = sfmlEvent->getIf()) { + event.type = sfEvtTouchMoved; + event.touch.finger = touchMoved->finger; + event.touch.position = {touchMoved->position.x, touchMoved->position.y}; + } else if (const auto *touchEnded = sfmlEvent->getIf()) { + event.type = sfEvtTouchEnded; + event.touch.finger = touchEnded->finger; + event.touch.position = {touchEnded->position.x, touchEnded->position.y}; + } else if (const auto *sensorChanged = sfmlEvent->getIf()) { + event.type = sfEvtSensorChanged; + event.sensor.sensorType = static_cast(sensorChanged->type); + event.sensor.value = {sensorChanged->value.x, sensorChanged->value.y, sensorChanged->value.z}; + } + + return true; +} diff --git a/CSFML/src/Window/Joystick.cpp b/CSFML/src/Window/Joystick.cpp index 505ebf2a..4bf2e42b 100644 --- a/CSFML/src/Window/Joystick.cpp +++ b/CSFML/src/Window/Joystick.cpp @@ -1,3 +1,4 @@ +#include "Window/Joystick.hpp" #include extern "C" bool sfJoystick_isConnected(unsigned int joystick) { @@ -8,16 +9,16 @@ extern "C" unsigned int sfJoystick_getButtonCount(unsigned int joystick) { return sf::Joystick::getButtonCount(joystick); } -extern "C" bool sfJoystick_hasAxis(unsigned int joystick, sf::Joystick::Axis axis) { - return sf::Joystick::hasAxis(joystick, axis); +extern "C" bool sfJoystick_hasAxis(unsigned int joystick, sfJoystickAxis axis) { + return sf::Joystick::hasAxis(joystick, static_cast(axis)); } extern "C" bool sfJoystick_isButtonPressed(unsigned int joystick, unsigned int button) { return sf::Joystick::isButtonPressed(joystick, button); } -extern "C" float sfJoystick_getAxisPosition(unsigned int joystick, sf::Joystick::Axis axis) { - return sf::Joystick::getAxisPosition(joystick, axis); +extern "C" float sfJoystick_getAxisPosition(unsigned int joystick, sfJoystickAxis axis) { + return sf::Joystick::getAxisPosition(joystick, static_cast(axis)); } extern "C" sf::Joystick::Identification *sfJoystick_getIdentification(unsigned int joystick) { diff --git a/CSFML/src/Window/Joystick.hpp b/CSFML/src/Window/Joystick.hpp new file mode 100644 index 00000000..b9503bd2 --- /dev/null +++ b/CSFML/src/Window/Joystick.hpp @@ -0,0 +1,12 @@ +#pragma once + +typedef enum { + sfJoystickX, + sfJoystickY, + sfJoystickZ, + sfJoystickR, + sfJoystickU, + sfJoystickV, + sfJoystickPovX, + sfJoystickPovY +} sfJoystickAxis; diff --git a/CSFML/src/Window/Keyboard.cpp b/CSFML/src/Window/Keyboard.cpp index 61ff374b..3de5f471 100644 --- a/CSFML/src/Window/Keyboard.cpp +++ b/CSFML/src/Window/Keyboard.cpp @@ -1,7 +1,25 @@ +#include "Window/Keyboard.hpp" +#include "SFML/System/String.hpp" #include -extern "C" bool sfKeyboard_isKeyPressed(sf::Keyboard::Key key) { - return sf::Keyboard::isKeyPressed(key); +extern "C" bool sfKeyboard_isKeyPressed(sfKeyCode key) { + return sf::Keyboard::isKeyPressed(static_cast(key)); +} + +extern "C" bool sfKeyboard_isScancodePressed(sfScancode code) { + return sf::Keyboard::isKeyPressed(static_cast(code)); +} + +extern "C" sfKeyCode sfKeyboard_localize(sfScancode code) { + return static_cast(sf::Keyboard::localize(static_cast(code))); +} + +extern "C" sfScancode sfKeyboard_delocalize(sfKeyCode code) { + return static_cast(sf::Keyboard::localize(static_cast(code))); +} + +extern "C" sf::String *sfKeyboard_getDescription(sfScancode code) { + return new sf::String(sf::Keyboard::getDescription(static_cast(code))); } extern "C" void sfKeyboard_setVirtualKeyboardVisible(bool visible) { diff --git a/CSFML/src/Window/Keyboard.hpp b/CSFML/src/Window/Keyboard.hpp new file mode 100644 index 00000000..0dcc46f5 --- /dev/null +++ b/CSFML/src/Window/Keyboard.hpp @@ -0,0 +1,257 @@ +#pragma once +typedef enum { + sfKeyUnknown = -1, + sfKeyA, + sfKeyB, + sfKeyC, + sfKeyD, + sfKeyE, + sfKeyF, + sfKeyG, + sfKeyH, + sfKeyI, + sfKeyJ, + sfKeyK, + sfKeyL, + sfKeyM, + sfKeyN, + sfKeyO, + sfKeyP, + sfKeyQ, + sfKeyR, + sfKeyS, + sfKeyT, + sfKeyU, + sfKeyV, + sfKeyW, + sfKeyX, + sfKeyY, + sfKeyZ, + sfKeyNum0, + sfKeyNum1, + sfKeyNum2, + sfKeyNum3, + sfKeyNum4, + sfKeyNum5, + sfKeyNum6, + sfKeyNum7, + sfKeyNum8, + sfKeyNum9, + sfKeyEscape, + sfKeyLControl, + sfKeyLShift, + sfKeyLAlt, + sfKeyLSystem, + sfKeyRControl, + sfKeyRShift, + sfKeyRAlt, + sfKeyRSystem, + sfKeyMenu, + sfKeyLBracket, + sfKeyRBracket, + sfKeySemicolon, + sfKeyComma, + sfKeyPeriod, + sfKeyApostrophe, + sfKeySlash, + sfKeyBackslash, + sfKeyGrave, + sfKeyEqual, + sfKeyHyphen, + sfKeySpace, + sfKeyEnter, + sfKeyBackspace, + sfKeyTab, + sfKeyPageUp, + sfKeyPageDown, + sfKeyEnd, + sfKeyHome, + sfKeyInsert, + sfKeyDelete, + sfKeyAdd, + sfKeySubtract, + sfKeyMultiply, + sfKeyDivide, + sfKeyLeft, + sfKeyRight, + sfKeyUp, + sfKeyDown, + sfKeyNumpad0, + sfKeyNumpad1, + sfKeyNumpad2, + sfKeyNumpad3, + sfKeyNumpad4, + sfKeyNumpad5, + sfKeyNumpad6, + sfKeyNumpad7, + sfKeyNumpad8, + sfKeyNumpad9, + sfKeyF1, + sfKeyF2, + sfKeyF3, + sfKeyF4, + sfKeyF5, + sfKeyF6, + sfKeyF7, + sfKeyF8, + sfKeyF9, + sfKeyF10, + sfKeyF11, + sfKeyF12, + sfKeyF13, + sfKeyF14, + sfKeyF15, + sfKeyPause, +} sfKeyCode; + +typedef enum { + sfScanUnknown = -1, + sfScanA = 0, + sfScanB, + sfScanC, + sfScanD, + sfScanE, + sfScanF, + sfScanG, + sfScanH, + sfScanI, + sfScanJ, + sfScanK, + sfScanL, + sfScanM, + sfScanN, + sfScanO, + sfScanP, + sfScanQ, + sfScanR, + sfScanS, + sfScanT, + sfScanU, + sfScanV, + sfScanW, + sfScanX, + sfScanY, + sfScanZ, + sfScanNum1, + sfScanNum2, + sfScanNum3, + sfScanNum4, + sfScanNum5, + sfScanNum6, + sfScanNum7, + sfScanNum8, + sfScanNum9, + sfScanNum0, + sfScanEnter, + sfScanEscape, + sfScanBackspace, + sfScanTab, + sfScanSpace, + sfScanHyphen, + sfScanEqual, + sfScanLBracket, + sfScanRBracket, + + sfScanBackslash, + sfScanSemicolon, + sfScanApostrophe, + sfScanGrave, + sfScanComma, + sfScanPeriod, + sfScanSlash, + sfScanF1, + sfScanF2, + sfScanF3, + sfScanF4, + sfScanF5, + sfScanF6, + sfScanF7, + sfScanF8, + sfScanF9, + sfScanF10, + sfScanF11, + sfScanF12, + sfScanF13, + sfScanF14, + sfScanF15, + sfScanF16, + sfScanF17, + sfScanF18, + sfScanF19, + sfScanF20, + sfScanF21, + sfScanF22, + sfScanF23, + sfScanF24, + sfScanCapsLock, + sfScanPrintScreen, + sfScanScrollLock, + sfScanPause, + sfScanInsert, + sfScanHome, + sfScanPageUp, + sfScanDelete, + sfScanEnd, + sfScanPageDown, + sfScanRight, + sfScanLeft, + sfScanDown, + sfScanUp, + sfScanNumLock, + sfScanNumpadDivide, + sfScanNumpadMultiply, + sfScanNumpadMinus, + sfScanNumpadPlus, + sfScanNumpadEqual, + sfScanNumpadEnter, + sfScanNumpadDecimal, + sfScanNumpad1, + sfScanNumpad2, + sfScanNumpad3, + sfScanNumpad4, + sfScanNumpad5, + sfScanNumpad6, + sfScanNumpad7, + sfScanNumpad8, + sfScanNumpad9, + sfScanNumpad0, + + sfScanNonUsBackslash, + sfScanApplication, + sfScanExecute, + sfScanModeChange, + sfScanHelp, + sfScanMenu, + sfScanSelect, + sfScanRedo, + sfScanUndo, + sfScanCut, + sfScanCopy, + sfScanPaste, + sfScanVolumeMute, + sfScanVolumeUp, + sfScanVolumeDown, + sfScanMediaPlayPause, + sfScanMediaStop, + sfScanMediaNextTrack, + sfScanMediaPreviousTrack, + sfScanLControl, + sfScanLShift, + sfScanLAlt, + sfScanLSystem, + sfScanRControl, + sfScanRShift, + sfScanRAlt, + sfScanRSystem, + sfScanBack, + sfScanForward, + sfScanRefresh, + sfScanStop, + sfScanSearch, + sfScanFavorites, + sfScanHomePage, + sfScanLaunchApplication1, + sfScanLaunchApplication2, + sfScanLaunchMail, + sfScanLaunchMediaSelect, +} sfScancode; diff --git a/CSFML/src/Window/Mouse.cpp b/CSFML/src/Window/Mouse.cpp index f4db91f8..ec63b1b1 100644 --- a/CSFML/src/Window/Mouse.cpp +++ b/CSFML/src/Window/Mouse.cpp @@ -1,23 +1,22 @@ +#include "Window/Mouse.hpp" #include "System/Vector2.hpp" #include #include -extern "C" bool sfMouse_isButtonPressed(sf::Mouse::Button button) { - return sf::Mouse::isButtonPressed(button); +extern "C" bool sfMouse_isButtonPressed(sfMouseButton button) { + return sf::Mouse::isButtonPressed(static_cast(button)); } extern "C" sfVector2i sfMouse_getPosition() { - sf::Vector2i pos = sf::Mouse::getPosition(); - return {pos.x, pos.y}; + return convertVector2(sf::Mouse::getPosition()); } extern "C" sfVector2i sfMouse_getPositionRelativeTo(const sf::Window *relativeTo) { - sf::Vector2i pos = sf::Mouse::getPosition(*relativeTo); - return {pos.x, pos.y}; + return convertVector2(sf::Mouse::getPosition(*relativeTo)); } extern "C" void sfMouse_setPosition(sfVector2i position) { - sf::Mouse::setPosition(sf::Vector2i(position.x, position.y)); + sf::Mouse::setPosition(convertVector2(position)); } extern "C" void sfMouse_setPositionRelativeTo(sfVector2i pos, const sf::Window *relativeTo) { diff --git a/CSFML/src/Window/Mouse.hpp b/CSFML/src/Window/Mouse.hpp new file mode 100644 index 00000000..c8a1f8d5 --- /dev/null +++ b/CSFML/src/Window/Mouse.hpp @@ -0,0 +1,14 @@ +#pragma once + +typedef enum { + sfMouseLeft, + sfMouseRight, + sfMouseMiddle, + sfMouseButtonExtra1, + sfMouseButtonExtra2, +} sfMouseButton; + +typedef enum { + sfMouseVerticalWheel, + sfMouseHorizontalWheel +} sfMouseWheel; diff --git a/CSFML/src/Window/Sensor.cpp b/CSFML/src/Window/Sensor.cpp index 1b9f6bac..2e500aa5 100644 --- a/CSFML/src/Window/Sensor.cpp +++ b/CSFML/src/Window/Sensor.cpp @@ -1,15 +1,15 @@ +#include "Window/Sensor.hpp" #include "System/Vector3.hpp" #include -extern "C" bool sfSensor_isAvailable(sf::Sensor::Type sensor) { - return sf::Sensor::isAvailable(sensor); +extern "C" bool sfSensor_isAvailable(sfSensorType sensor) { + return sf::Sensor::isAvailable(static_cast(sensor)); } -extern "C" void sfSensor_setEnabled(sf::Sensor::Type sensor, bool enabled) { - sf::Sensor::setEnabled(sensor, enabled); +extern "C" void sfSensor_setEnabled(sfSensorType sensor, bool enabled) { + sf::Sensor::setEnabled(static_cast(sensor), enabled); } -extern "C" sfVector3f sfSensor_getValue(sf::Sensor::Type sensor) { - sf::Vector3f val = sf::Sensor::getValue(sensor); - return {val.x, val.y, val.z}; +extern "C" sfVector3f sfSensor_getValue(sfSensorType sensor) { + return convertVector3(sf::Sensor::getValue(static_cast(sensor))); } diff --git a/CSFML/src/Window/Sensor.hpp b/CSFML/src/Window/Sensor.hpp new file mode 100644 index 00000000..889da1e1 --- /dev/null +++ b/CSFML/src/Window/Sensor.hpp @@ -0,0 +1,10 @@ +#pragma once + +typedef enum { + sfSensorAccelerometer, + sfSensorGyroscope, + sfSensorMagnetometer, + sfSensorGravity, + sfSensorUserAcceleration, + sfSensorOrientation, +} sfSensorType; diff --git a/CSFML/src/Window/Touch.cpp b/CSFML/src/Window/Touch.cpp index 3094d47d..c8c2bc60 100644 --- a/CSFML/src/Window/Touch.cpp +++ b/CSFML/src/Window/Touch.cpp @@ -7,11 +7,9 @@ extern "C" bool sfTouch_isDown(unsigned int finger) { } extern "C" sfVector2i sfTouch_getPosition(unsigned int finger) { - sf::Vector2i pos = sf::Touch::getPosition(finger); - return {pos.x, pos.y}; + return convertVector2(sf::Touch::getPosition(finger)); } extern "C" sfVector2i sfTouch_getPositionRelativeTo(unsigned int finger, const sf::Window *relativeTo) { - sf::Vector2i pos = sf::Touch::getPosition(finger, *relativeTo); - return {pos.x, pos.y}; + return convertVector2(sf::Touch::getPosition(finger, *relativeTo)); } diff --git a/CSFML/src/Window/VideoMode.cpp b/CSFML/src/Window/VideoMode.cpp index d1d295ca..1dbc4f12 100644 --- a/CSFML/src/Window/VideoMode.cpp +++ b/CSFML/src/Window/VideoMode.cpp @@ -4,8 +4,7 @@ #include extern "C" sfVideoMode sfVideoMode_getDesktopMode(void) { - sf::VideoMode vm = sf::VideoMode::getDesktopMode(); - return {vm.width, vm.height, vm.bitsPerPixel}; + return convertVideoMode(sf::VideoMode::getDesktopMode()); } extern "C" const std::vector *sfVideoMode_getFullscreenModes() { @@ -13,7 +12,7 @@ extern "C" const std::vector *sfVideoMode_getFullscreenModes() { } extern "C" bool sfVideoMode_isValid(sfVideoMode mode) { - return sf::VideoMode(mode.width, mode.height, mode.bitsPerPixel).isValid(); + return convertVideoMode(mode).isValid(); } extern "C" std::size_t sfVideoModeVector_getLength(const std::vector *vec) { diff --git a/CSFML/src/Window/VideoMode.hpp b/CSFML/src/Window/VideoMode.hpp index 235d13cf..a4fab45d 100644 --- a/CSFML/src/Window/VideoMode.hpp +++ b/CSFML/src/Window/VideoMode.hpp @@ -1,10 +1,22 @@ -#ifndef SFML_VIDEOMODE_H -#define SFML_VIDEOMODE_H +#pragma once +#include +#include "System/Vector2.hpp" struct sfVideoMode { - unsigned int width; - unsigned int height; + sfVector2u size; unsigned int bitsPerPixel; }; -#endif // SFML_VIDEOMODE_H +//////////////////////////////////////////////////////////// +// Convert sf::VideoMode to sfVideoMode +//////////////////////////////////////////////////////////// +[[nodiscard]] inline sfVideoMode convertVideoMode(const sf::VideoMode &videoMode) { + return {{videoMode.size.x, videoMode.size.y}, videoMode.bitsPerPixel}; +} + +//////////////////////////////////////////////////////////// +// Convert sfVideoMode to sf::VideoMode +//////////////////////////////////////////////////////////// +[[nodiscard]] inline sf::VideoMode convertVideoMode(const sfVideoMode &videoMode) { + return sf::VideoMode({videoMode.size.x, videoMode.size.y}, videoMode.bitsPerPixel); +} diff --git a/CSFML/src/Window/Window.cpp b/CSFML/src/Window/Window.cpp index 7855672b..91e975f0 100644 --- a/CSFML/src/Window/Window.cpp +++ b/CSFML/src/Window/Window.cpp @@ -1,8 +1,27 @@ +#include "SFML/System/Time.hpp" +#include "SFML/System/Vector2.hpp" #include "System/Vector2.hpp" #include "Window/VideoMode.hpp" +#include "Window/Window.hpp" +#include "Window/Event.hpp" +#include #include #include +#include #include +#include +#include + +sf::State to_state(const sfState state) { + switch (state) { + case sfState::Windowed: + return sf::State::Windowed; + case sfState::Fullscreen: + return sf::State::Fullscreen; + default: + throw std::invalid_argument("Unreachable Pattern"); + } +} extern "C" sf::Window *sfWindow_new() { return new sf::Window; @@ -13,10 +32,8 @@ extern "C" void sfWindow_del(sf::Window *window) { } // Create with (mode, title, style, settings) -extern "C" void sfWindow_create_mtss(sf::Window *window, sfVideoMode mode, const uint32_t *title, uint32_t style, const sf::ContextSettings *settings) { - // Convert video mode - sf::VideoMode videoMode(mode.width, mode.height, mode.bitsPerPixel); - window->create(videoMode, title, style, *settings); +extern "C" void sfWindow_create_mtsss(sf::Window *window, sfVideoMode mode, const uint32_t *title, uint32_t style, sfState state, const sf::ContextSettings *settings) { + window->create(convertVideoMode(mode), (char32_t *)title, style, to_state(state), *settings); } extern "C" void sfWindow_create_handle_settings(sf::Window *window, sf::WindowHandle handle, const sf::ContextSettings *settings) { @@ -35,38 +52,52 @@ extern "C" const sf::ContextSettings *sfWindow_getSettings(const sf::Window *win return &window->getSettings(); } -extern "C" bool sfWindow_pollEvent(sf::Window *window, sf::Event *event) { - return window->pollEvent(*event); +extern "C" bool sfWindow_pollEvent(sf::Window *window, sfEvent *event) { + return convertEvent(window->pollEvent(), *event); } -extern "C" bool sfWindow_waitEvent(sf::Window *window, sf::Event *event) { - return window->waitEvent(*event); +extern "C" bool sfWindow_waitEvent(sf::Window *window, sfEvent *event, const int64_t timeout) { + return convertEvent(window->waitEvent(sf::Time(std::chrono::microseconds(timeout))), *event); } extern "C" sfVector2i sfWindow_getPosition(const sf::Window *window) { - sf::Vector2i pos = window->getPosition(); - return {pos.x, pos.y}; + return convertVector2(window->getPosition()); } extern "C" void sfWindow_setPosition(sf::Window *window, sfVector2i position) { - window->setPosition(sf::Vector2i(position.x, position.y)); + window->setPosition(convertVector2(position)); } extern "C" sfVector2u sfWindow_getSize(const sf::Window *window) { - sf::Vector2u size = window->getSize(); - return {size.x, size.y}; + return convertVector2(window->getSize()); } extern "C" void sfWindow_setSize(sf::Window *window, sfVector2u size) { - window->setSize(sf::Vector2u(size.x, size.y)); + window->setSize(convertVector2(size)); +} + +extern "C" void sfWindow_setMinimumSize(sf::Window *window, const sfVector2u *size) { + if (size == nullptr) { + window->setMinimumSize(std::nullopt); + } else { + window->setMinimumSize(std::optional({size->x, size->y})); + } +} + +extern "C" void sfWindow_setMaximumSize(sf::Window *window, const sfVector2u *size) { + if (size == nullptr) { + window->setMaximumSize(std::nullopt); + } else { + window->setMaximumSize(std::optional({size->x, size->y})); + } } extern "C" void sfWindow_setUnicodeTitle(sf::Window *window, const uint32_t *title) { - window->setTitle(title); + window->setTitle((char32_t *)title); } -extern "C" void sfWindow_setIcon(sf::Window *window, unsigned int width, unsigned int height, const uint8_t *pixels) { - window->setIcon(width, height, pixels); +extern "C" void sfWindow_setIcon(sf::Window *window, sfVector2u size, const uint8_t *pixels) { + window->setIcon(convertVector2(size), pixels); } extern "C" void sfWindow_setVisible(sf::Window *window, bool visible) { @@ -118,6 +149,6 @@ extern "C" void sfWindow_setJoystickThreshold(sf::Window *window, float threshol window->setJoystickThreshold(threshold); } -extern "C" sf::WindowHandle sfWindow_getSystemHandle(const sf::Window *window) { - return window->getSystemHandle(); +extern "C" sf::WindowHandle sfWindow_getNativeHandle(const sf::Window *window) { + return window->getNativeHandle(); } diff --git a/CSFML/src/Window/Window.hpp b/CSFML/src/Window/Window.hpp new file mode 100644 index 00000000..b58062a1 --- /dev/null +++ b/CSFML/src/Window/Window.hpp @@ -0,0 +1,10 @@ +#pragma once + +#include + +enum sfState { + Windowed, + Fullscreen +}; + +sf::State to_state(const sfState state); diff --git a/Cargo.toml b/Cargo.toml index ccbc3623..9413f841 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -14,7 +14,6 @@ rust-version = "1.86" exclude = [ "SFML/doc", "SFML/examples", - "SFML/tools", "SFML/extlibs/bin", "SFML/extlibs/libs-android", "SFML/extlibs/libs-ios", @@ -24,10 +23,6 @@ exclude = [ "SFML/extlibs/libs-mingw/x64/libogg.a", "SFML/extlibs/libs-mingw/x86/libFLAC.a", "SFML/extlibs/libs-mingw/x86/libogg.a", - "SFML/extlibs/libs-msvc/x64/flac.lib", - "SFML/extlibs/libs-msvc/x64/ogg.lib", - "SFML/extlibs/libs-msvc/x86/flac.lib", - "SFML/extlibs/libs-msvc/x86/ogg.lib", "SFML/extlibs/libs-msvc-universal/x86/flac.lib", "SFML/extlibs/libs-msvc-universal/x86/ogg.lib", "SFML/extlibs/libs-msvc-universal/x64/flac.lib", diff --git a/SFML b/SFML index 5383d2b3..016bea94 160000 --- a/SFML +++ b/SFML @@ -1 +1 @@ -Subproject commit 5383d2b3948f805af55c9f8a4587ac72ec5981d1 +Subproject commit 016bea9491ccafc3529019fe1d403885a8b3a6ae diff --git a/TODO.md b/TODO.md new file mode 100644 index 00000000..29f606af --- /dev/null +++ b/TODO.md @@ -0,0 +1,21 @@ +# DESCRIPTION + +A list of missing crap that needs to be done... at some point. + +Also, just because something is not on this list and it seems like it is missing to you, doesn't mean it is not +missing! There may be more things todo that are not mentioned here! If you just want to add onto the TODO list, +just make a PR. What would be more appreciated is if you made a PR implementing it. If you do that, you MUST +include usage in the examples or write example doc code! + +Thanks! + +# Missing implementation + +sfRenderWindow_drawVertexBufferRange +sfRenderwindow_createVulkanSurface +sfRenderTexture_drawVertexBufferRange +All of the vulkan crap +handleEvents + +# Other stuff +window-test example crashes if you keep selecting new window sizes quickly on linux. (It also crashes in rust-sfml 2.6 versioning) diff --git a/build.rs b/build.rs index f9eb7827..9db8b5c6 100644 --- a/build.rs +++ b/build.rs @@ -42,7 +42,7 @@ fn static_link_windows( .into(); // Copy only needed SFML extlibs to out dir to avoid linking every ext lib. // We don't need libFLAC, because we build it ourselves. - for lib in ["freetype", "openal32", "vorbisenc", "vorbisfile", "vorbis"] { + for lib in ["freetype", "vorbisenc", "vorbisfile", "vorbis"] { let lib_name = env.lib_filename(lib); let from = sfml_extlibs_path.join(&lib_name); let to = build_lib_path.join(&lib_name); @@ -53,6 +53,7 @@ fn static_link_windows( } println!("cargo:rustc-link-lib=dylib=winmm"); println!("cargo:rustc-link-lib=dylib=user32"); + println!("cargo:rustc-link-lib=dylib=advapi32"); if feat_window { println!("cargo:rustc-link-lib=dylib=opengl32"); println!("cargo:rustc-link-lib=dylib=gdi32"); @@ -61,7 +62,6 @@ fn static_link_windows( println!("cargo:rustc-link-lib=static=freetype"); } if feat_audio { - println!("cargo:rustc-link-lib=static=openal32"); flac_ogg_linkage.link("FLAC"); println!("cargo:rustc-link-lib=static=vorbisenc"); println!("cargo:rustc-link-lib=static=vorbisfile"); @@ -80,6 +80,7 @@ fn static_link_linux( if feat_window { println!("cargo:rustc-link-lib=dylib=GL"); println!("cargo:rustc-link-lib=dylib=X11"); + println!("cargo:rustc-link-lib=Xi"); println!("cargo:rustc-link-lib=dylib=Xcursor"); println!("cargo:rustc-link-lib=dylib=Xrandr"); } @@ -87,8 +88,6 @@ fn static_link_linux( unix_graphics_link_support_libs(); } if feat_audio { - // We link openal separately because Mac Os has its own OpenAL framework - pkgconfig_probe_with_fallback("openal", "rustc-link-lib=dylib=openal"); unix_audio_link_support_libs(flac_ogg_linkage); } } @@ -151,6 +150,20 @@ impl WinEnv { } fn main() { + // Need to probe Cargo's env as build.rs uses the default toolchain to + // run the build meaning that #[cfg(..)]'s won't work + let is_windows = env::var("CARGO_CFG_WINDOWS").is_ok(); + let is_unix = env::var("CARGO_CFG_UNIX").is_ok(); + let is_linux = env::var("CARGO_CFG_TARGET_OS") + .map(|os| os == "linux") + .unwrap_or(false); + let is_macos = env::var("CARGO_CFG_TARGET_OS") + .map(|os| os == "macos") + .unwrap_or(false); + if is_macos { + link_mac_os_frameworks(); + } + println!("cargo:rerun-if-changed=CSFML"); println!("cargo:rerun-if-changed=SFML"); let feat_audio = env::var("CARGO_FEATURE_AUDIO").is_ok(); @@ -168,12 +181,21 @@ fn main() { // we cannot support debug builds of SFML. cmake.profile("Release"); cmake + .define("CMAKE_FIND_DEBUG_MODE", "TRUE") + .define("BUILD_SHARED_LIBS", "FALSE") + .define("SFML_BUILD_NETWORK", "FALSE") + .define("SFML_INSTALL_PKGCONFIG_FILES", "FALSE") + .define("CMAKE_CXX_STANDARD", "17") + .define("CMAKE_CXX_STANDARD_REQUIRED", "ON") .define("CMAKE_FIND_DEBUG_MODE", "TRUE") // I think I'll leave this on for now. Useful for debugging. .define("BUILD_SHARED_LIBS", "FALSE") .define("SFML_BUILD_NETWORK", "FALSE") .define("SFML_INSTALL_PKGCONFIG_FILES", "FALSE") // Disable "install" step .no_build_target(true); + if is_windows { + cmake.cxxflag("/std:c++17").cxxflag("/EHsc"); + } if !feat_audio { cmake.define("SFML_BUILD_AUDIO", "FALSE"); } else { @@ -217,7 +239,6 @@ fn main() { let mut build = cc::Build::new(); build .cpp(true) - .flag_if_supported("--std=c++17") .define("CSFML_SYSTEM_EXPORTS", None) .define("CSFML_AUDIO_EXPORTS", None) .define("CSFML_WINDOW_EXPORTS", None) @@ -225,6 +246,11 @@ fn main() { .define("SFML_STATIC", None) .include("CSFML/src/") .include("SFML/include"); + if is_windows { + build.flag_if_supported("/std:c++17"); + } else { + build.flag_if_supported("--std=c++17"); + } build.files( [ "CSFML/src/System/Clock.cpp", @@ -233,6 +259,7 @@ fn main() { "CSFML/src/System/SfString.cpp", "CSFML/src/System/SfStdString.cpp", "CSFML/src/System/SfStdVector.cpp", + "CSFML/src/System/Buffer.cpp", ] .iter(), ); @@ -242,6 +269,7 @@ fn main() { "CSFML/src/Audio/Listener.cpp", "CSFML/src/Audio/Music.cpp", "CSFML/src/Audio/Sound.cpp", + "CSFML/src/Audio/SoundChannel.cpp", "CSFML/src/Audio/SoundBuffer.cpp", "CSFML/src/Audio/SoundBufferRecorder.cpp", "CSFML/src/Audio/SoundRecorder.cpp", @@ -291,19 +319,6 @@ fn main() { ); } build.compile("rcsfml"); - // Need to probe Cargo's env as build.rs uses the default toolchain to - // run the build meaning that #[cfg(..)]'s won't work - let is_windows = env::var("CARGO_CFG_WINDOWS").is_ok(); - let is_unix = env::var("CARGO_CFG_UNIX").is_ok(); - let is_linux = env::var("CARGO_CFG_TARGET_OS") - .map(|os| os == "linux") - .unwrap_or(false); - let is_macos = env::var("CARGO_CFG_TARGET_OS") - .map(|os| os == "macos") - .unwrap_or(false); - if is_macos { - link_mac_os_frameworks(); - } let link_search = if matches!(win_env, Some(WinEnv::Msvc)) { "build/lib/Release" } else { @@ -369,5 +384,4 @@ fn link_mac_os_frameworks() { println!("cargo:rustc-link-lib=framework=IOKit"); println!("cargo:rustc-link-lib=framework=Carbon"); println!("cargo:rustc-link-lib=framework=AppKit"); - println!("cargo:rustc-link-lib=framework=OpenAL"); } diff --git a/examples/borrowed-resources.rs b/examples/borrowed-resources.rs index d6e06daf..47d80983 100644 --- a/examples/borrowed-resources.rs +++ b/examples/borrowed-resources.rs @@ -16,6 +16,7 @@ fn main() -> SfResult<()> { (800, 600), "Borrowed resources", Style::CLOSE, + Default::default(), &Default::default(), )?; window.set_vertical_sync_enabled(true); @@ -32,9 +33,8 @@ fn main() -> SfResult<()> { circle.set_position((100.0, 100.0)); // Create a Sprite. - let mut sprite = Sprite::new(); + let mut sprite = Sprite::with_texture(&frank); // Have it use the same texture as the circle. - sprite.set_texture(&frank, true); sprite.set_position((400.0, 300.0)); sprite.set_scale(0.5); @@ -50,19 +50,10 @@ fn main() -> SfResult<()> { // Create an initialized text using the font. let title = Text::new("Borrowed resources example!", &font, 50); - // Create a second text using the same font. - // This time, we create and initialize it separately. - let mut second_text = Text::default(); - second_text.set_string("This text shares the same font with the title!"); - second_text.set_font(&font); - second_text.set_fill_color(Color::GREEN); - second_text.set_position((10.0, 350.0)); - second_text.set_character_size(20); - // Create a third text using the same font. - let mut third_text = Text::new("This one too!", &font, 20); - third_text.set_position((300.0, 100.0)); - third_text.set_fill_color(Color::RED); + let mut second_text = Text::new("This one too!", &font, 20); + second_text.set_position((300.0, 100.0)); + second_text.set_fill_color(Color::RED); 'mainloop: loop { while let Some(event) = window.poll_event() { @@ -81,7 +72,6 @@ fn main() -> SfResult<()> { window.draw(&convex_shape); window.draw(&title); window.draw(&second_text); - window.draw(&third_text); // Little test here for `Shape::points` let mut circ = CircleShape::new(4.0, 30); diff --git a/examples/clock.rs b/examples/clock.rs index 21a89f4d..6e556b7f 100644 --- a/examples/clock.rs +++ b/examples/clock.rs @@ -9,7 +9,8 @@ use { }; fn main() -> Result<(), SfError> { - let clock = Clock::start()?; + let mut clock = Clock::new()?; + clock.start(); while clock.elapsed_time().as_seconds() < 5.0 { print!("Elapsed time: {}\r", clock.elapsed_time().as_seconds()); let _ = std::io::stdout().flush(); diff --git a/examples/cursor.rs b/examples/cursor.rs index 8c23c911..1c8ffb0f 100644 --- a/examples/cursor.rs +++ b/examples/cursor.rs @@ -3,7 +3,7 @@ use sfml::{ graphics::{ Color, Font, Rect, RectangleShape, RenderTarget, RenderWindow, Shape, Text, Transformable, }, - system::Vector2, + system::{Vector2, Vector2i}, window::{ContextSettings, Cursor, CursorType, Event, Style, mouse}, }; @@ -21,8 +21,8 @@ fn gridindex( grid.get_mut(y * DRAW_GRID_WH as usize + x) } -fn mouse_over(rect: &Rect, mouse_x: i32, mouse_y: i32) -> bool { - rect.contains(Vector2::new(mouse_x, mouse_y)) +fn mouse_over(rect: &Rect, mouse_position: Vector2i) -> bool { + rect.contains(mouse_position) } enum ButtonStyle { @@ -40,8 +40,8 @@ fn draw_button( render_window: &mut RenderWindow, style: ButtonStyle, ) { - shape.set_position((rect.left as f32, rect.top as f32)); - shape.set_size((rect.width as f32, rect.height as f32)); + shape.set_position(rect.position.as_other()); + shape.set_size(rect.size.as_other()); let (rect_fill, rect_outline, text_fill) = match style { ButtonStyle::Normal => (Color::TRANSPARENT, Color::WHITE, Color::WHITE), ButtonStyle::Highlighted => (Color::WHITE, Color::WHITE, Color::BLACK), @@ -50,7 +50,7 @@ fn draw_button( }; shape.set_outline_color(rect_outline); shape.set_fill_color(rect_fill); - text.set_position((rect.left as f32 + 12.0, rect.top as f32 + 8.0)); + text.set_position((rect.position.x as f32 + 12.0, rect.position.y as f32 + 8.0)); text.set_fill_color(text_fill); text.set_string(string); render_window.draw(shape); @@ -71,21 +71,20 @@ fn bstyle(highlighted: bool, selected: bool, error: bool) -> ButtonStyle { fn main() -> SfResult<()> { example_ensure_right_working_dir(); - - let mut cursor = Cursor::from_system(CursorType::Arrow)?; let mut rw = RenderWindow::new( (800, 800), "SFML cursor example", Style::CLOSE, + Default::default(), &ContextSettings::default(), )?; rw.set_vertical_sync_enabled(true); let font = Font::from_file("sansation.ttf")?; let mut failed_index = usize::MAX; let mut selected_index = usize::MAX; - let set_button = Rect::new(348, 500, 100, 32); - let hotspot_button = Rect::new(458, 500, 100, 32); - let clear_button = Rect::new(568, 500, 100, 32); + let set_button = Rect::new(Vector2::new(348, 500), Vector2::new(100, 32)); + let hotspot_button = Rect::new(Vector2::new(458, 500), Vector2::new(100, 32)); + let clear_button = Rect::new(Vector2::new(568, 500), Vector2::new(100, 32)); let mut pixel_grid = [false; DRAW_GRID_WH as usize * DRAW_GRID_WH as usize]; let mut hotspot_selection = false; let mut hotspot_selected = false; @@ -117,7 +116,10 @@ fn main() -> SfResult<()> { CursorType::NotAllowed, ]; for i in 0..cursor_types.len() { - buttons.push(Rect::new(16, 16 + i as i32 * 36, 250, 32)); + buttons.push(Rect::new( + Vector2::new(16, 16 + i as i32 * 36), + Vector2::new(250, 32), + )); } while rw.is_open() { @@ -126,13 +128,12 @@ fn main() -> SfResult<()> { Event::Closed => rw.close(), Event::MouseButtonPressed { button: mouse::Button::Left, - x, - y, + position, } => { for (i, b) in buttons.iter().enumerate() { - if mouse_over(b, x, y) { - match cursor.load_from_system(cursor_types[i]) { - Ok(()) => { + if mouse_over(b, position) { + match Cursor::from_system(cursor_types[i]) { + Ok(cursor) => { unsafe { rw.set_mouse_cursor(&cursor); } @@ -145,7 +146,7 @@ fn main() -> SfResult<()> { } } } - if mouse_over(&set_button, x, y) { + if mouse_over(&set_button, position) { let mut pixels = [0; DRAW_GRID_WH as usize * DRAW_GRID_WH as usize * 4]; for (i, px) in pixel_grid.iter().enumerate() { let offset = i * 4; @@ -157,12 +158,12 @@ fn main() -> SfResult<()> { } } unsafe { - match cursor.load_from_pixels( + match Cursor::from_pixels( &pixels, Vector2::new(DRAW_GRID_WH as u32, DRAW_GRID_WH as u32), hotspot, ) { - Ok(()) => { + Ok(cursor) => { rw.set_mouse_cursor(&cursor); } Err(e) => { @@ -172,13 +173,13 @@ fn main() -> SfResult<()> { } modif = false; } - if mouse_over(&clear_button, x, y) { + if mouse_over(&clear_button, position) { for px in pixel_grid.iter_mut() { *px = false; } modif = true; } - if mouse_over(&hotspot_button, x, y) { + if mouse_over(&hotspot_button, position) { hotspot_selection = true; } } @@ -201,17 +202,17 @@ fn main() -> SfResult<()> { let mp = rw.mouse_position(); let mut highlight_index = usize::MAX; for (i, b) in buttons.iter().enumerate() { - if mouse_over(b, mp.x, mp.y) { + if mouse_over(b, mp) { highlight_index = i; } } - if mouse_over(&set_button, mp.x, mp.y) { + if mouse_over(&set_button, mp) { set_button_highlighted = true; } - if mouse_over(&hotspot_button, mp.x, mp.y) { + if mouse_over(&hotspot_button, mp) { hotspot_button_highlighted = true; } - if mouse_over(&clear_button, mp.x, mp.y) { + if mouse_over(&clear_button, mp) { clear_button_highlighted = true; } // Grid interactions diff --git a/examples/custom-drawable.rs b/examples/custom-drawable.rs index a141e754..27e2c7e4 100644 --- a/examples/custom-drawable.rs +++ b/examples/custom-drawable.rs @@ -43,6 +43,7 @@ fn main() -> SfResult<()> { [800, 600], "Custom drawable", Style::CLOSE, + Default::default(), &Default::default(), )?; window.set_vertical_sync_enabled(true); diff --git a/examples/custom-shape.rs b/examples/custom-shape.rs index d4452203..41d63ed7 100644 --- a/examples/custom-shape.rs +++ b/examples/custom-shape.rs @@ -3,7 +3,7 @@ use sfml::{ graphics::{ Color, CustomShape, CustomShapePoints, RenderTarget, RenderWindow, Shape, Transformable, }, - system::{Clock, Vector2f}, + system::{Angle, Clock, Vector2f}, window::{Event, Key, Style}, }; @@ -48,9 +48,11 @@ fn main() -> SfResult<()> { [800, 600], "Custom shape", Style::DEFAULT, + Default::default(), &Default::default(), )?; - let clock = Clock::start()?; + let mut clock = Clock::new()?; + clock.start(); window.set_vertical_sync_enabled(true); let mut shape = CustomShape::new(Box::new(TriangleShape)); @@ -71,7 +73,7 @@ fn main() -> SfResult<()> { let t = clock.elapsed_time().as_seconds(); - shape.set_rotation(t.sin().abs() * 360.0); + shape.set_rotation(Angle::degrees(t.sin().abs() * 360.0)); let scale = t.cos().abs(); shape.set_scale(scale); shape.set_fill_color(hue_time(t)); diff --git a/examples/custom-sound-recorder.rs b/examples/custom-sound-recorder.rs index 783b2d7c..c9bfcf79 100644 --- a/examples/custom-sound-recorder.rs +++ b/examples/custom-sound-recorder.rs @@ -1,6 +1,6 @@ use { sfml::{ - audio::{Sound, SoundBuffer, SoundRecorder, SoundRecorderDriver, capture}, + audio::{Sound, SoundBuffer, SoundChannel, SoundRecorder, SoundRecorderDriver, capture}, graphics::{Color, Font, RectangleShape, RenderTarget, RenderWindow, Text, Transformable}, window::{Event, Key, Style}, }, @@ -75,6 +75,7 @@ fn main() -> Result<(), Box> { (800, 600), "Custom sound recorder", Style::CLOSE, + Default::default(), &Default::default(), )?; rw.set_vertical_sync_enabled(true); @@ -85,7 +86,7 @@ fn main() -> Result<(), Box> { let mut started = false; let mut snd_buf = SoundBuffer::new()?; let mut samp_accum = Vec::new(); - let mut sound = Some(Sound::new()); + let mut sound = Some(Sound::new(&snd_buf)); let mut selected_dev_idx = 0; let mut mode = Mode::Main; let mut input_buf = String::new(); @@ -106,6 +107,7 @@ fn main() -> Result<(), Box> { &samp_accum[..], desired_channel_count, desired_sample_rate, + &[SoundChannel::Mono], )?; samp_accum.clear(); started = false; diff --git a/examples/custom-sound-stream.rs b/examples/custom-sound-stream.rs index 2185dedd..d5238c10 100644 --- a/examples/custom-sound-stream.rs +++ b/examples/custom-sound-stream.rs @@ -1,5 +1,8 @@ use sfml::{ - audio::{SoundStatus, SoundStream, SoundStreamPlayer}, + audio::{ + SoundChannel, SoundStream, SoundStreamPlayer, + sound_source::{self, SoundSource}, + }, system::Time, }; @@ -42,6 +45,10 @@ impl SoundStream for BitMelody { fn sample_rate(&self) -> u32 { 44_100 } + + fn get_channel_map(&self) -> Vec { + [SoundChannel::Mono].to_vec() + } } impl BitMelody { @@ -62,7 +69,7 @@ fn main() { let total_dur = stream.total_duration_samples() as f32 / stream.sample_rate() as f32; let mut player = SoundStreamPlayer::new(&mut stream); player.play(); - while player.status() == SoundStatus::PLAYING { + while player.status() == sound_source::Status::Playing { let current = player.playing_offset().as_seconds(); eprint!("Playing custom sound stream: {current:06.03}/{total_dur:06.03}\r"); std::thread::sleep(std::time::Duration::from_millis(100)); diff --git a/examples/mouse.rs b/examples/mouse.rs index d6eb7cde..85a3f83a 100644 --- a/examples/mouse.rs +++ b/examples/mouse.rs @@ -9,6 +9,7 @@ fn main() -> SfResult<()> { (800, 600), "Mouse events", Style::CLOSE, + Default::default(), &Default::default(), )?; window.set_mouse_cursor_visible(false); @@ -32,21 +33,47 @@ fn main() -> SfResult<()> { while let Some(ev) = window.poll_event() { match ev { Event::Closed => break 'mainloop, - Event::MouseWheelScrolled { wheel, delta, x, y } => { - push_text!(x, y, "Scroll: {:?}, {}, {}, {}", wheel, delta, x, y); + Event::MouseWheelScrolled { + wheel, + delta, + position, + } => { + push_text!( + position.x, + position.y, + "Scroll: {:?}, {}, {}, {}", + wheel, + delta, + position.x, + position.y + ); } - Event::MouseButtonPressed { button, x, y } => { - push_text!(x, y, "Press: {:?}, {}, {}", button, x, y); + Event::MouseButtonPressed { button, position } => { + push_text!( + position.x, + position.y, + "Press: {:?}, {}, {}", + button, + position.x, + position.y + ); } - Event::MouseButtonReleased { button, x, y } => { - push_text!(x, y, "Release: {:?}, {}, {}", button, x, y); + Event::MouseButtonReleased { button, position } => { + push_text!( + position.x, + position.y, + "Release: {:?}, {}, {}", + button, + position.x, + position.y + ); } Event::KeyPressed { code, .. } => { if code == Key::W { window.set_mouse_position(Vector2i::new(400, 300)); } else if code == Key::D { let dm = VideoMode::desktop_mode(); - let center = Vector2i::new(dm.width as i32 / 2, dm.height as i32 / 2); + let center = Vector2i::new(dm.size.x as i32 / 2, dm.size.y as i32 / 2); mouse::set_desktop_position(center); } else if code == Key::V { cursor_visible = !cursor_visible; @@ -87,7 +114,7 @@ fn main() -> SfResult<()> { .global_bounds() .intersection(&texts[j].global_bounds()) { - texts[j].move_((0., -intersect.height)); + texts[j].move_((0., -intersect.size.y)); } } } diff --git a/examples/music-stream.rs b/examples/music-stream.rs index f2ae9054..2b2424de 100644 --- a/examples/music-stream.rs +++ b/examples/music-stream.rs @@ -1,6 +1,9 @@ use { sfml::{ - audio::{Music, SoundStatus}, + audio::{ + Music, + sound_source::{self, SoundSource}, + }, system::{InputStream, Time, sleep}, }, std::{error::Error, fs::File, io::Write}, @@ -23,7 +26,7 @@ fn main() -> Result<(), Box> { music.play(); - while music.status() == SoundStatus::PLAYING { + while music.status() == sound_source::Status::Playing { // Leave some CPU time for other processes sleep(Time::milliseconds(100)); // Display the playing position diff --git a/examples/opengl.rs b/examples/opengl.rs index b3a5afc0..90acd82b 100644 --- a/examples/opengl.rs +++ b/examples/opengl.rs @@ -30,13 +30,13 @@ fn main() -> SfResult<()> { (800, 600), "SFML graphics with OpenGL", Style::default(), + Default::default(), &ctx_sett, )?; window.set_vertical_sync_enabled(true); let mut bg_tex = Texture::new()?; - bg_tex.set_srgb(srgb); - bg_tex.load_from_file("opengl-background.jpg", IntRect::default())?; + bg_tex.load_from_file("opengl-background.jpg", srgb, IntRect::default())?; let bg_sprite = Sprite::with_texture(&bg_tex); let font = Font::from_file("sansation.ttf")?; @@ -103,7 +103,8 @@ fn main() -> SfResult<()> { } window.set_active(false)?; - let clock = Clock::start()?; + let mut clock = Clock::new()?; + clock.start(); let mut mipmap_enabled = true; while window.is_open() { @@ -136,10 +137,10 @@ fn main() -> SfResult<()> { srgb = !srgb; window.close(); } - Event::Resized { width, height } => { + Event::Resized { size } => { window.set_active(true)?; unsafe { - gl::glViewport(0, 0, width as _, height as _); + gl::glViewport(0, 0, size.x as _, size.y as _); } window.set_active(false)?; } diff --git a/examples/pong.rs b/examples/pong.rs index 400cb015..4e77ad79 100644 --- a/examples/pong.rs +++ b/examples/pong.rs @@ -2,13 +2,13 @@ use { rand::{Rng as _, SeedableRng, rngs::SmallRng}, sfml::{ SfResult, - audio::{Sound, SoundBuffer, SoundSource}, + audio::{Sound, SoundBuffer, sound_source::SoundSource}, graphics::{ CircleShape, Color, Font, RectangleShape, RenderTarget, RenderWindow, Shape, Text, Transformable, }, system::{Clock, Time, Vector2f}, - window::{ContextSettings, Event, Key, Scancode, Style}, + window::{ContextSettings, Event, Key, Scancode, Style, window_enums::State}, }, std::{env, f32::consts::PI}, }; @@ -48,6 +48,7 @@ fn main() -> SfResult<()> { [game_width, game_height], "SFML Pong", Style::CLOSE, + State::Windowed, &context_settings, )?; let context_settings = window.settings(); @@ -88,21 +89,24 @@ fn main() -> SfResult<()> { let font = Font::from_file("sansation.ttf")?; // Initialize the pause message - let mut pause_message = Text::default(); - pause_message.set_font(&font); - pause_message.set_character_size(40); + let mut pause_message = Text::new( + "Welcome to SFML pong!\nPress space to start the game", + &font, + 40, + ); pause_message.set_position((170., 150.)); pause_message.set_fill_color(Color::WHITE); - pause_message.set_string("Welcome to SFML pong!\nPress space to start the game"); // Define the paddles properties - let mut ai_timer = Clock::start()?; + let mut ai_timer = Clock::new()?; + ai_timer.start(); let paddle_speed = 400.; let mut right_paddle_speed = 0.; let mut ball_speed = 400.; let mut ball_angle = 0.; - let mut clock = Clock::start()?; + let mut clock = Clock::new()?; + clock.start(); let mut is_playing = false; let mut up = false; let mut down = false; diff --git a/examples/positional-audio.rs b/examples/positional-audio.rs index 5bc0f028..68912fd5 100644 --- a/examples/positional-audio.rs +++ b/examples/positional-audio.rs @@ -1,11 +1,11 @@ use { sfml::{ - audio::{Music, SoundSource, listener}, + audio::{Music, listener, sound_source::SoundSource}, graphics::{ CircleShape, Color, FloatRect, Font, RectangleShape, RenderStates, RenderTarget, RenderWindow, Shape, Text, Transformable, }, - system::{Clock, Vector2, Vector2f, Vector3}, + system::{Angle, Clock, Vector2, Vector2f, Vector3}, window::{Event, Key, Style}, }, std::error::Error, @@ -14,18 +14,16 @@ use { include!("../example_common.rs"); /// Convert a line between two points to an equivalent rotated rectangle -fn line_to_rect(x1: f32, y1: f32, x2: f32, y2: f32, thickness: f32) -> (FloatRect, f32) { +fn line_to_rect(x1: f32, y1: f32, x2: f32, y2: f32, thickness: f32) -> (FloatRect, Angle) { let dx = x2 - x1; let dy = y2 - y1; ( FloatRect { - left: x1, - top: y1 - thickness / 2.0, - width: (dx * dx + dy * dy).sqrt(), - height: thickness, + position: Vector2::new(x1, y1 - thickness / 2.), + size: Vector2::new((dx * dx + dy * dy).sqrt(), thickness), }, - dy.atan2(dx).to_degrees(), + Angle::radians(dy.atan2(dx)), ) } @@ -50,6 +48,7 @@ fn main() -> Result<(), Box> { (800, 600), "Positional audio demo", Style::CLOSE, + sfml::window::window_enums::State::Windowed, &Default::default(), )?; rw.set_vertical_sync_enabled(true); @@ -69,7 +68,8 @@ fn main() -> Result<(), Box> { let mut listener_pos = Vector3::new(0.0, 0.0, 0.0); let center = Vector2::new(400., 300.); let [mut go_left, mut go_right, mut go_up, mut go_down] = [false; 4]; - let clock = Clock::start()?; + let mut clock = Clock::new()?; + clock.start(); while rw.is_open() { while let Some(ev) = rw.poll_event() { diff --git a/examples/rc-resources.rs b/examples/rc-resources.rs index 21f3582a..7bfa86df 100644 --- a/examples/rc-resources.rs +++ b/examples/rc-resources.rs @@ -5,17 +5,20 @@ use sfml::{ Shape, Sprite, Texture, Transformable, }, system::Vector2f, - window::{Event, Key, Style, clipboard}, + window::{Event, Key, Style, clipboard, window_enums::State}, }; include!("../example_common.rs"); +enum EitherResource { + Sprite(RcSprite), + Text(RcText), +} + struct FloatingResource { up: bool, left: bool, - render_sprite: bool, - sprite: RcSprite, - text: RcText, + either_resource: EitherResource, speed: f32, } @@ -24,80 +27,76 @@ impl FloatingResource { Self { up, left, - sprite: RcSprite::with_texture(texture), - text: Default::default(), + either_resource: EitherResource::Sprite(RcSprite::with_texture(texture)), speed, - render_sprite: true, } } fn with_font(font: &RcFont, up: bool, left: bool, speed: f32) -> Self { - let mut self_ = Self { + let mut text = RcText::new("", font, 16); + text.scale(Vector2f::new(2., 2.)); + Self { up, left, - sprite: Default::default(), - text: RcText::new("", font, 16), + either_resource: EitherResource::Text(text), speed, - render_sprite: false, - }; - self_.text.scale(Vector2f::new(2., 2.)); - - self_ + } } fn render(&self, window: &mut RenderWindow) { - if self.render_sprite { - window.draw(&self.sprite) - } else { - window.draw(&self.text) + match &self.either_resource { + EitherResource::Sprite(sprite) => window.draw(sprite), + EitherResource::Text(text) => window.draw(text), } } fn move_resources(&mut self, window_size: Vector2f) { - if self.render_sprite { - // Modify the sprite position freely - if self.sprite.position().y <= 0f32 { - self.up = false; - } - if self.sprite.position().y + self.sprite.global_bounds().height >= window_size.y { - self.up = true; - } - if self.sprite.position().x <= 0f32 { - self.left = false; - } - if self.sprite.position().x + self.sprite.global_bounds().width >= window_size.x { - self.left = true; - } + match &mut self.either_resource { + EitherResource::Sprite(sprite) => { + if sprite.position().y <= 0f32 { + self.up = false; + } + if sprite.position().y + sprite.global_bounds().size.y >= window_size.y { + self.up = true; + } + if sprite.position().x <= 0f32 { + self.left = false; + } + if sprite.position().x + sprite.global_bounds().size.x >= window_size.x { + self.left = true; + } - self.sprite.set_position( - self.sprite.position() - + Vector2f::new( - if self.left { -self.speed } else { self.speed }, - if self.up { -self.speed } else { self.speed }, - ), - ); - } else { - // Modify the sprite position freely - if self.text.position().y <= 0f32 { - self.up = false; - } - if self.text.position().y + self.text.global_bounds().height >= window_size.y { - self.up = true; - } - if self.text.position().x <= 0f32 { - self.left = false; - } - if self.text.position().x + self.text.global_bounds().width >= window_size.x { - self.left = true; + sprite.set_position( + sprite.position() + + Vector2f::new( + if self.left { -self.speed } else { self.speed }, + if self.up { -self.speed } else { self.speed }, + ), + ); } + EitherResource::Text(text) => { + // Modify the sprite position freely + if text.position().y <= 0f32 { + self.up = false; + } + if text.position().y + text.global_bounds().size.y >= window_size.y { + self.up = true; + } + if text.position().x <= 0f32 { + self.left = false; + } + if text.position().x + text.global_bounds().size.x >= window_size.x { + self.left = true; + } - self.text.set_position( - self.text.position() - + Vector2f::new( - if self.left { -self.speed } else { self.speed }, - if self.up { -self.speed } else { self.speed }, - ), - ); + text.set_position( + text.position() + + Vector2f::new( + if self.left { -self.speed } else { self.speed }, + if self.up { -self.speed } else { self.speed }, + ), + ); + } } } } @@ -121,8 +120,13 @@ fn get_set_smooth_rc_text(font: &RcFont) -> RcText { fn main() -> SfResult<()> { example_ensure_right_working_dir(); - let mut window = - RenderWindow::new((800, 600), "SFML window", Style::CLOSE, &Default::default())?; + let mut window = RenderWindow::new( + (800, 600), + "SFML window", + Style::CLOSE, + State::Windowed, + &Default::default(), + )?; window.set_framerate_limit(60); // Create a new texture. @@ -189,7 +193,9 @@ fn main() -> SfResult<()> { // Update floating_resource positions so they move around on the screen for floating_resource in &mut floating_resources { floating_resource.move_resources(Vector2f::new(800f32, 600f32)); - floating_resource.text.set_string(&text_buf); + if let EitherResource::Text(text) = &mut floating_resource.either_resource { + text.set_string(&text_buf); + } } window.clear(Color::BLACK); diff --git a/examples/resource-holder.rs b/examples/resource-holder.rs index 354e99d4..717cfc9f 100644 --- a/examples/resource-holder.rs +++ b/examples/resource-holder.rs @@ -6,7 +6,7 @@ use { audio::{Sound, SoundBuffer}, cpp::FBox, graphics::{Color, RenderTarget, RenderWindow, Sprite, Texture}, - window::{Event, Key, Style}, + window::{Event, Key, Style, window_enums::State}, }, std::{collections::HashMap, hash::Hash}, }; @@ -63,6 +63,7 @@ fn main() -> SfResult<()> { (800, 600), "Resource holder test", Style::CLOSE, + State::Windowed, &Default::default(), )?; rw.set_vertical_sync_enabled(true); diff --git a/examples/shader.rs b/examples/shader.rs index f999ab2f..af2db99d 100644 --- a/examples/shader.rs +++ b/examples/shader.rs @@ -8,8 +8,8 @@ use { RenderTexture, RenderWindow, Shader, ShaderType, Sprite, Text, Texture, Transform, Transformable, Vertex, }, - system::{Clock, Vector2f}, - window::{Event, Key, Style}, + system::{Clock, Vector2, Vector2f}, + window::{Event, Key, Style, window_enums::State}, }, }; @@ -27,10 +27,8 @@ struct Pixelate<'t> { impl<'t> Pixelate<'t> { fn new(texture: &'t Texture) -> SfResult { - let mut sprite = Sprite::new(); - sprite.set_texture(texture, false); Ok(Self { - sprite, + sprite: Sprite::with_texture(texture), shader: Shader::from_file("pixelate.frag", ShaderType::Fragment)?, }) } @@ -182,7 +180,7 @@ struct Edge<'t> { impl<'t> Edge<'t> { fn new(bg_texture: &'t Texture, entity_texture: &'t Texture) -> SfResult { - let mut surface = RenderTexture::new(800, 600)?; + let mut surface = RenderTexture::new(Vector2::new(800, 600))?; surface.set_smooth(true); let mut bg_sprite = Sprite::with_texture(bg_texture); bg_sprite.set_position((135., 100.)); @@ -191,7 +189,7 @@ impl<'t> Edge<'t> { for i in 0..6 { entities.push(Sprite::with_texture_and_rect( entity_texture, - IntRect::new(96 * i, 0, 96, 96), + IntRect::new(Vector2::new(96 * i, 0), Vector2::new(96, 96)), )); } @@ -302,7 +300,7 @@ impl Drawable for Geometry<'_> { impl Effect for Geometry<'_> { fn update(&mut self, _t: f32, x: f32, y: f32) -> SfResult<()> { self.transform = Transform::IDENTITY; - self.transform.translate(400., 300.); + self.transform.translate(Vector2::new(400., 300.)); self.transform.rotate(x * 360.0); let size = 25. + y.abs() * 50.; self.shader.set_uniform_vec2("size", size.into())?; @@ -321,6 +319,7 @@ fn main() -> SfResult<()> { (800, 600), "SFML Shader", Style::TITLEBAR | Style::CLOSE, + State::Windowed, &Default::default(), )?; window.set_vertical_sync_enabled(true); @@ -351,7 +350,8 @@ fn main() -> SfResult<()> { let mut instructions = Text::new(msg, &font, 20); instructions.set_position((280., 555.)); instructions.set_fill_color(Color::rgb(80, 80, 80)); - let clock = Clock::start()?; + let mut clock = Clock::new()?; + clock.start(); while window.is_open() { while let Some(event) = window.poll_event() { diff --git a/examples/sound-capture.rs b/examples/sound-capture.rs index bec13328..198da0f9 100644 --- a/examples/sound-capture.rs +++ b/examples/sound-capture.rs @@ -1,6 +1,9 @@ use { sfml::{ - audio::{Sound, SoundBufferRecorder, SoundStatus, capture}, + audio::{ + Sound, SoundBufferRecorder, capture, + sound_source::{self, SoundSource}, + }, system::{Time, sleep}, }, std::{ @@ -110,7 +113,7 @@ fn main() -> Result<(), Box> { sound.play(); - while sound.status() == SoundStatus::PLAYING { + while sound.status() == sound_source::Status::Playing { // Display the playing position print!( "\rPlaying... {:.2} sec", diff --git a/examples/sound.rs b/examples/sound.rs index edf7f062..c36c3176 100644 --- a/examples/sound.rs +++ b/examples/sound.rs @@ -1,7 +1,10 @@ use { sfml::{ SfResult, - audio::{Music, Sound, SoundBuffer, SoundStatus}, + audio::{ + Music, Sound, SoundBuffer, + sound_source::{self, SoundSource}, + }, system::{Time, sleep}, }, std::io::Write, @@ -22,7 +25,7 @@ fn play_sound() -> SfResult<()> { let mut sound = Sound::with_buffer(&buffer); sound.play(); - while sound.status() == SoundStatus::PLAYING { + while sound.status() == sound_source::Status::Playing { // Display the playing position print!("\rPlaying... {:.2}", sound.playing_offset().as_seconds()); let _ = std::io::stdout().flush(); @@ -45,7 +48,7 @@ fn play_music() -> SfResult<()> { music.play(); - while music.status() == SoundStatus::PLAYING { + while music.status() == sound_source::Status::Playing { // Display the playing position print!("\rPlaying... {:.2}", music.playing_offset().as_seconds()); let _ = std::io::stdout().flush(); diff --git a/examples/spritemark.rs b/examples/spritemark.rs index 8f435a6c..365b44de 100644 --- a/examples/spritemark.rs +++ b/examples/spritemark.rs @@ -67,6 +67,7 @@ fn main() -> SfResult<()> { native_mode, "Spritemark", Style::default(), + Default::default(), &ContextSettings::default(), )?; window.set_position(Vector2::new(0, 0)); @@ -82,10 +83,10 @@ fn main() -> SfResult<()> { let mut rs = RenderStates::default(); let mut buf = Vec::new(); let mut frames_rendered = 0; - let mut sec_clock = Clock::start()?; + let mut sec_clock = Clock::new()?; + sec_clock.start(); let mut fps = 0; let mut lmb_down = false; - let mut view = View::new()?; while window.is_open() { while let Some(event) = window.poll_event() { @@ -107,8 +108,8 @@ fn main() -> SfResult<()> { } => { lmb_down = false; } - Event::Resized { width, height } => { - view.reset(Rect::new(0., 0., width as f32, height as f32)); + Event::Resized { size } => { + let view = View::from_rect(Rect::new(Vector2::new(0., 0.), size.as_other())); window.set_view(&view); } _ => {} @@ -127,18 +128,22 @@ fn main() -> SfResult<()> { }); } } - for obj in &mut objects { let size = f32::from(SUBIMAGE_SIZE); let tex_x = f32::from(obj.image_id) * size; let mut tf = Transform::default(); - tf.translate(obj.position.x, obj.position.y); - tf.rotate_with_center(obj.angle, size / 2.0, size / 2.0); + tf.translate(obj.position); + tf.rotate_with_center(obj.angle, Vector2::new(size / 2., size / 2.)); buf.push(Vertex { color: Color::WHITE, position: tf.transform_point(Vector2f::new(0., 0.)), tex_coords: Vector2f::new(tex_x, 0.), }); + buf.push(Vertex { + color: Color::WHITE, + position: tf.transform_point(Vector2f::new(size, 0.)), + tex_coords: Vector2f::new(tex_x + size, 0.), + }); buf.push(Vertex { color: Color::WHITE, position: tf.transform_point(Vector2f::new(0., size)), @@ -146,19 +151,25 @@ fn main() -> SfResult<()> { }); buf.push(Vertex { color: Color::WHITE, - position: tf.transform_point(Vector2f::new(size, size)), - tex_coords: Vector2f::new(tex_x + size, size), + position: tf.transform_point(Vector2f::new(0., size)), + tex_coords: Vector2f::new(tex_x, size), }); buf.push(Vertex { color: Color::WHITE, position: tf.transform_point(Vector2f::new(size, 0.)), tex_coords: Vector2f::new(tex_x + size, 0.), }); + buf.push(Vertex { + color: Color::WHITE, + position: tf.transform_point(Vector2f::new(size, size)), + tex_coords: Vector2f::new(tex_x + size, size), + }); obj.update(window.size().y as f32, window.size().x as f32); } + window.clear(Color::BLACK); rs.texture = Some(&texture); - window.draw_primitives(&buf, PrimitiveType::QUADS, &rs); + window.draw_primitives(&buf, PrimitiveType::TRIANGLES, &rs); rs.texture = None; text.set_string(&format!("{} sprites\n{fps} fps", objects.len())); window.draw_text(&text, &rs); diff --git a/examples/unicode-text-entry.rs b/examples/unicode-text-entry.rs index 3070c60f..0a3c3884 100644 --- a/examples/unicode-text-entry.rs +++ b/examples/unicode-text-entry.rs @@ -4,7 +4,7 @@ use sfml::{ Color, Font, RectangleShape, RenderTarget, RenderWindow, Shape, Text, TextStyle, Transformable, }, - window::{Event, Key, Style, clipboard}, + window::{Event, Key, Style, clipboard, window_enums::State}, }; include!("../example_common.rs"); @@ -16,6 +16,7 @@ fn main() -> SfResult<()> { (800, 600), "◢◤ Unicode text entry ◥◣", Style::CLOSE, + State::Windowed, &Default::default(), )?; window.set_vertical_sync_enabled(true); @@ -24,7 +25,7 @@ fn main() -> SfResult<()> { let mut font = Font::new()?; match std::env::args().nth(1) { - Some(path) => font.load_from_file(&path)?, + Some(path) => font.open_from_file(&path)?, None => font.load_from_memory_static(include_bytes!("resources/sansation.ttf"))?, }; let mut string = String::from("This text can be edited.\nTry it!"); diff --git a/examples/vertex-arrays.rs b/examples/vertex-arrays.rs index 4099dc00..4e00cc6c 100644 --- a/examples/vertex-arrays.rs +++ b/examples/vertex-arrays.rs @@ -12,6 +12,7 @@ fn main() -> SfResult<()> { (800, 600), "Vertex array example", Style::CLOSE, + Default::default(), &Default::default(), )?; window.set_vertical_sync_enabled(true); diff --git a/examples/vertex-buffers.rs b/examples/vertex-buffers.rs index 96911ce6..718d7c2b 100644 --- a/examples/vertex-buffers.rs +++ b/examples/vertex-buffers.rs @@ -3,7 +3,7 @@ use sfml::{ graphics::{ Color, PrimitiveType, RenderTarget, RenderWindow, Vertex, VertexBuffer, VertexBufferUsage, }, - window::{Event, Style, mouse::Button}, + window::{Event, Style, mouse::Button, window_enums::State}, }; fn main() -> SfResult<()> { @@ -11,6 +11,7 @@ fn main() -> SfResult<()> { (800, 600), "SFML VertexBuffer accessors Example", Style::CLOSE, + State::Windowed, &Default::default(), )?; window.set_vertical_sync_enabled(true); @@ -36,11 +37,10 @@ fn main() -> SfResult<()> { Event::Closed => break 'mainloop, Event::MouseButtonPressed { button: Button::Left, - x, - y, + position, } => { vertices.push(Vertex::with_pos_color( - (x as f32, y as f32).into(), + (position.x as f32, position.y as f32).into(), Color::GREEN, )); vertex_buffer.update(&vertices, 0)?; diff --git a/examples/window-test.rs b/examples/window-test.rs index 5e34f382..d4549fc2 100644 --- a/examples/window-test.rs +++ b/examples/window-test.rs @@ -1,7 +1,7 @@ use sfml::{ SfResult, graphics::{Color, Font, RenderTarget, RenderWindow, Text, Transformable}, - window::{ContextSettings, Event, Key, Style, VideoMode}, + window::{ContextSettings, Event, Key, Style, VideoMode, window_enums::State}, }; struct WindowConfig { @@ -33,6 +33,7 @@ fn main() -> SfResult<()> { configs[cfg_idx].mode, "Window test", Style::CLOSE, + State::Windowed, &ContextSettings::default(), )?; let font = Font::from_memory_static(include_bytes!("resources/sansation.ttf"))?; @@ -51,15 +52,24 @@ fn main() -> SfResult<()> { } Key::Enter => match configs.get(cfg_idx) { Some(cfg) => { - rw.recreate(cfg.mode, cfg.title, cfg.style, &ContextSettings::default()) + rw = RenderWindow::new( + cfg.mode, + cfg.title, + cfg.style, + State::Windowed, + &ContextSettings::default(), + )? } None => match fs_modes.get(cfg_idx - configs.len()) { - Some(mode) => rw.recreate( - *mode, - "Fullscreen", - Style::FULLSCREEN, - &ContextSettings::default(), - ), + Some(mode) => { + rw = RenderWindow::new( + *mode, + "Fullscreen", + Default::default(), + State::Fullscreen, + &ContextSettings::default(), + )? + } None => { eprintln!("Invalid index: {cfg_idx}"); } @@ -113,7 +123,7 @@ fn main() -> SfResult<()> { txt.set_position((x, y)); txt.set_string(&format!( "{}x{}x{}", - mode.width, mode.height, mode.bits_per_pixel + mode.size.x, mode.size.y, mode.bits_per_pixel )); rw.draw(&txt); i += 1; diff --git a/src/audio/capture.rs b/src/audio/capture.rs index aaf73575..d8574c40 100644 --- a/src/audio/capture.rs +++ b/src/audio/capture.rs @@ -4,7 +4,6 @@ use { audio::SoundBuffer, cpp::{CppString, CppVector, FBox}, ffi::audio as ffi, - system::Time, }, std::{ffi::CString, os::raw::c_void, ptr::NonNull}, }; @@ -193,22 +192,6 @@ impl<'a, R: SoundRecorder> SoundRecorderDriver<'a, R> { pub fn channel_count(&self) -> u32 { unsafe { ffi::sfCustomSoundRecorder_getChannelCount(self.handle.as_ptr()) } } - /// Set the processing interval. - /// - /// The processing interval controls the period between calls to - /// [`SoundRecorder::on_process_samples`]. - /// You may want to use a small interval if you want to process the recorded data in real time, - /// for example. - /// - /// Note: this is only a hint, the actual period may vary. - /// So don't rely on this parameter to implement precise timing. - /// - /// The default processing interval is 100 ms. - pub fn set_processing_interval(&mut self, interval: Time) { - unsafe { - ffi::sfCustomSoundRecorder_setProcessingInterval(self.handle.as_ptr(), interval.raw()) - } - } /// Get the name of the current audio capture device. #[must_use] pub fn device(&self) -> &CppString { @@ -338,6 +321,32 @@ impl SoundBufferRecorder { unsafe { ffi::sfSoundBufferRecorder_setDevice(self.handle.as_ptr(), name.as_ptr()) }; success.into_sf_result() } + + /// Get the number of channels used by this recorder + /// + /// Currently only mono and stereo are supported, so the + /// value is either 1 (for mono) or 2 (for stereo). + /// + /// Number of channels + #[must_use] + pub fn channel_count(&self) -> u32 { + unsafe { ffi::sfSoundBufferRecorder_getChannelCount(self.handle.as_ptr()) } + } + + /// Set the channel count of the audio capture device + /// + /// This method allows you to specify the number of channels + /// used for recording. Currently only 16-bit mono and + /// 16-bit stereo are supported. + /// + /// # Arguments + /// channelCount - Number of channels. Currently only + /// mono (1) and stereo (2) are supported. + pub fn set_channel_count(&mut self, channel_count: u32) { + unsafe { + ffi::sfSoundBufferRecorder_setChannelCount(self.handle.as_ptr(), channel_count); + } + } } #[cfg_attr(not(feature = "ci-headless"), test)] diff --git a/src/audio/listener.rs b/src/audio/listener.rs index a38c3b7b..bf07b9aa 100644 --- a/src/audio/listener.rs +++ b/src/audio/listener.rs @@ -27,7 +27,41 @@ //! [`View`]: crate::graphics::View //! -use crate::{ffi, system::Vector3f}; +use std::f32::consts::PI; + +use crate::{ + ffi, + system::{Angle, Vector3f}, +}; + +/// Structure defining the properties of a directional cone +/// +/// Sounds will play at gain 1 when they are positioned +/// within the inner angle of the cone. Sounds will play +/// at `outerGain` when they are positioned outside the +/// outer angle of the cone. The gain declines linearly +/// from 1 to `outerGain` as the sound moves from the inner +/// angle to the outer angle. +#[repr(C)] +#[derive(Debug, PartialEq, Clone, Copy)] +pub struct Cone { + /// Inner angle, in degrees + pub inner_angle: Angle, + /// Outer angle, in degrees + pub outer_angle: Angle, + /// Outer gain + pub outer_gain: f32, +} + +impl Default for Cone { + fn default() -> Self { + Self { + inner_angle: Angle::degrees(2. * PI), + outer_angle: Angle::degrees(2. * PI), + outer_gain: 1., + } + } +} /// Change the global volume of all the sounds and musics /// @@ -104,3 +138,30 @@ pub fn set_up_vector(value: Vector3f) { pub fn up_vector() -> Vector3f { unsafe { ffi::audio::sfListener_getUpVector() } } + +/// Get the current forward vector of the listener in the scene +#[must_use] +pub fn velocity() -> Vector3f { + unsafe { ffi::audio::sfListener_getVelocity() } +} + +/// Set the velocity of the listener in the scene +/// +/// The default listener's velocity is (0, 0, -1). +pub fn set_velocity(velocity: Vector3f) { + unsafe { ffi::audio::sfListener_setVelocity(velocity) } +} + +/// Set the cone properties of the listener in the audio scene +/// +/// The cone defines how directional attenuation is applied. +/// The default cone of a sound is (2 * PI, 2 * PI, 1). +pub fn set_cone(cone: Cone) { + unsafe { ffi::audio::sfListener_setCone(cone.into()) } +} + +/// Get the cone properties of the listener in the audio scene +#[must_use] +pub fn cone() -> Cone { + unsafe { ffi::audio::sfListener_getCone().into() } +} diff --git a/src/audio/mod.rs b/src/audio/mod.rs index bbf3a63f..8ee96fef 100644 --- a/src/audio/mod.rs +++ b/src/audio/mod.rs @@ -7,8 +7,7 @@ pub use self::{ music::Music, sound::Sound, sound_buffer::SoundBuffer, - sound_source::SoundSource, - sound_status::SoundStatus, + sound_channel::SoundChannel, sound_stream::{SoundStream, SoundStreamPlayer}, time_span::TimeSpan, }; @@ -19,7 +18,8 @@ pub mod listener; mod music; mod sound; mod sound_buffer; -mod sound_source; -mod sound_status; +mod sound_channel; +/// Types and traits for dealing with audio playback +pub mod sound_source; mod sound_stream; mod time_span; diff --git a/src/audio/music.rs b/src/audio/music.rs index accb7d2c..47f09a9c 100644 --- a/src/audio/music.rs +++ b/src/audio/music.rs @@ -1,12 +1,14 @@ use { + super::{sound_channel::SoundChannel, sound_source::SoundSource}, crate::{ IntoSfResult, SfResult, - audio::{SoundSource, SoundStatus, TimeSpan}, - ffi::{self}, + audio::TimeSpan, + cpp::CppVector, + ffi, system::{InputStream, Time, Vector3f}, }, std::{ - ffi::CString, + ffi::{CString, c_uint, c_void}, io::{Read, Seek}, marker::PhantomData, }, @@ -168,7 +170,7 @@ impl Music<'_> { /// Return true if the music is looping, false otherwise #[must_use] pub fn is_looping(&self) -> bool { - unsafe { ffi::audio::sfMusic_getLoop(self.music) } + unsafe { ffi::audio::sfMusic_isLooping(self.music) } } /// Get the total duration of a music /// @@ -197,12 +199,15 @@ impl Music<'_> { unsafe { ffi::audio::sfMusic_getSampleRate(self.music) } } - /// Get the current status of a music (stopped, paused, playing) + /// Get the map of position in sample frame to sound channel /// - /// Return current status + /// This is used to map a sample in the sample stream to a + /// position during spatialization. + /// + /// Return Map of position in sample frame to sound channel #[must_use] - pub fn status(&self) -> SoundStatus { - unsafe { SoundStatus(ffi::audio::sfMusic_getStatus(self.music)) } + pub fn channel_map(&self) -> &'static CppVector { + unsafe { &*ffi::audio::sfMusic_getChannelMap(self.music) } } /// Get the current playing position of a music @@ -240,7 +245,7 @@ impl Music<'_> { /// /// By default, the music will *not* loop. pub fn set_looping(&mut self, looping: bool) { - unsafe { ffi::audio::sfMusic_setLoop(self.music, looping) } + unsafe { ffi::audio::sfMusic_setLooping(self.music, looping) } } /// Change the current playing position of a music /// @@ -304,6 +309,90 @@ impl SoundSource for Music<'_> { fn attenuation(&self) -> f32 { unsafe { ffi::audio::sfMusic_getAttenuation(self.music) } } + fn set_pan(&mut self, pan: f32) { + unsafe { ffi::audio::sfMusic_setPan(self.music, pan) } + } + fn set_spatialization_enabled(&mut self, enabled: bool) { + unsafe { ffi::audio::sfMusic_setSpatializationEnabled(self.music, enabled) } + } + fn set_direction>(&mut self, direction: P) { + unsafe { ffi::audio::sfMusic_setDirection(self.music, direction.into()) } + } + fn set_cone(&mut self, cone: super::sound_source::Cone) { + unsafe { ffi::audio::sfMusic_setCone(self.music, cone.into()) } + } + fn set_velocity>(&mut self, velocity: P) { + unsafe { ffi::audio::sfMusic_setVelocity(self.music, velocity.into()) } + } + fn set_doppler_factor(&mut self, factor: f32) { + unsafe { ffi::audio::sfMusic_setDopplerFactor(self.music, factor) } + } + fn set_directional_attenuation_factor(&mut self, factor: f32) { + unsafe { ffi::audio::sfMusic_setDirectionalAttenuationFactor(self.music, factor) } + } + fn set_max_distance(&mut self, distance: f32) { + unsafe { ffi::audio::sfMusic_setMaxDistance(self.music, distance) } + } + fn set_min_gain(&mut self, gain: f32) { + unsafe { ffi::audio::sfMusic_setMinGain(self.music, gain) } + } + fn set_max_gain(&mut self, gain: f32) { + unsafe { ffi::audio::sfMusic_setMaxGain(self.music, gain) } + } + fn set_effect_processor(&mut self, effect_processor: super::sound_source::EffectProcessor) { + let (cb, user_data) = match effect_processor { + Some(cb) => { + let boxed = Box::new(cb); + let trampoline: unsafe extern "C" fn( + *const f32, + *mut c_uint, + *mut f32, + *mut c_uint, + c_uint, + *mut c_void, + ) = ffi::audio::effect_processor_trampoline; + (Some(trampoline), Box::into_raw(boxed).cast::()) + } + None => (None, std::ptr::null_mut()), + }; + + unsafe { + ffi::audio::sfMusic_setEffectProcessor(self.music, cb, user_data); + } + } + fn pan(&self) -> f32 { + unsafe { ffi::audio::sfMusic_getPan(self.music) } + } + fn is_spatialization_enabled(&self) -> bool { + unsafe { ffi::audio::sfMusic_isSpatializationEnabled(self.music) } + } + fn direction(&self) -> Vector3f { + unsafe { ffi::audio::sfMusic_getDirection(self.music) } + } + fn cone(&self) -> super::sound_source::Cone { + unsafe { ffi::audio::sfMusic_getCone(self.music).into() } + } + fn velocity(&self) -> Vector3f { + unsafe { ffi::audio::sfMusic_getVelocity(self.music) } + } + fn doppler_factor(&self) -> f32 { + unsafe { ffi::audio::sfMusic_getDopplerFactor(self.music) } + } + fn directional_attenuation_factor(&self) -> f32 { + unsafe { ffi::audio::sfMusic_getDirectionalAttenuationFactor(self.music) } + } + fn get_max_distance(&self) -> f32 { + unsafe { ffi::audio::sfMusic_getMaxDistance(self.music) } + } + fn get_min_gain(&self) -> f32 { + unsafe { ffi::audio::sfMusic_getMinGain(self.music) } + } + fn get_max_gain(&self) -> f32 { + unsafe { ffi::audio::sfMusic_getMaxGain(self.music) } + } + fn status(&self) -> super::sound_source::Status { + unsafe { ffi::audio::sfMusic_getStatus(self.music) } + } } impl Drop for Music<'_> { diff --git a/src/audio/sound.rs b/src/audio/sound.rs index c0c8eebd..ad24fd26 100644 --- a/src/audio/sound.rs +++ b/src/audio/sound.rs @@ -1,10 +1,15 @@ use { + super::sound_source::SoundSource, crate::{ - audio::{SoundBuffer, SoundSource, SoundStatus}, + audio::SoundBuffer, ffi, system::{Time, Vector3f}, }, - std::{marker::PhantomData, ptr::NonNull}, + std::{ + ffi::{c_uint, c_void}, + marker::PhantomData, + ptr::NonNull, + }, }; /// Regular sound that can be played in the audio environment. @@ -50,8 +55,8 @@ impl<'buf> Sound<'buf> { /// /// Panics on allocation failure #[must_use] - pub fn new() -> Self { - let s = unsafe { ffi::audio::sfSound_new() }; + pub fn new(sound_buffer: &'buf SoundBuffer) -> Self { + let s = unsafe { ffi::audio::sfSound_new(sound_buffer) }; Sound { handle: NonNull::new(s).expect("Failed to create Sound"), buffer: PhantomData, @@ -61,7 +66,7 @@ impl<'buf> Sound<'buf> { /// Create a new `Sound` with a buffer #[must_use] pub fn with_buffer(buffer: &'buf SoundBuffer) -> Self { - let mut s = Sound::new(); + let mut s = Sound::new(buffer); s.set_buffer(buffer); s } @@ -105,15 +110,7 @@ impl<'buf> Sound<'buf> { /// Return true if the sound is looping, false otherwise #[must_use] pub fn is_looping(&self) -> bool { - unsafe { ffi::audio::sfSound_getLoop(self.handle.as_ptr()) } - } - - /// Get the current status of a sound (stopped, paused, playing) - /// - /// Return current status - #[must_use] - pub fn status(&self) -> SoundStatus { - unsafe { SoundStatus(ffi::audio::sfSound_getStatus(self.handle.as_ptr())) } + unsafe { ffi::audio::sfSound_isLooping(self.handle.as_ptr()) } } /// Get the current playing position of a sound @@ -136,7 +133,7 @@ impl<'buf> Sound<'buf> { impl<'buf> Sound<'buf> { /// Sets whether this sound should loop or not. pub fn set_looping(&mut self, looping: bool) { - unsafe { ffi::audio::sfSound_setLoop(self.handle.as_ptr(), looping) } + unsafe { ffi::audio::sfSound_setLooping(self.handle.as_ptr(), looping) } } /// Change the current playing position of a sound @@ -159,12 +156,6 @@ impl<'buf> Sound<'buf> { } } -impl Default for Sound<'_> { - fn default() -> Self { - Self::new() - } -} - impl Clone for Sound<'_> { fn clone(&self) -> Self { let s = unsafe { ffi::audio::sfSound_cpy(self.handle.as_ptr()) }; @@ -212,6 +203,90 @@ impl SoundSource for Sound<'_> { fn attenuation(&self) -> f32 { unsafe { ffi::audio::sfSound_getAttenuation(self.handle.as_ptr()) } } + fn set_pan(&mut self, pan: f32) { + unsafe { ffi::audio::sfSound_setPan(self.handle.as_ptr(), pan) } + } + fn set_spatialization_enabled(&mut self, enabled: bool) { + unsafe { ffi::audio::sfSound_setSpatializationEnabled(self.handle.as_ptr(), enabled) } + } + fn set_direction>(&mut self, direction: P) { + unsafe { ffi::audio::sfSound_setDirection(self.handle.as_ptr(), direction.into()) } + } + fn set_cone(&mut self, cone: super::sound_source::Cone) { + unsafe { ffi::audio::sfSound_setCone(self.handle.as_ptr(), cone.into()) } + } + fn set_velocity>(&mut self, velocity: P) { + unsafe { ffi::audio::sfSound_setVelocity(self.handle.as_ptr(), velocity.into()) } + } + fn set_doppler_factor(&mut self, factor: f32) { + unsafe { ffi::audio::sfSound_setDopplerFactor(self.handle.as_ptr(), factor) } + } + fn set_directional_attenuation_factor(&mut self, factor: f32) { + unsafe { ffi::audio::sfSound_setDirectionalAttenuationFactor(self.handle.as_ptr(), factor) } + } + fn set_max_distance(&mut self, distance: f32) { + unsafe { ffi::audio::sfSound_setMaxDistance(self.handle.as_ptr(), distance) } + } + fn set_min_gain(&mut self, gain: f32) { + unsafe { ffi::audio::sfSound_setMinGain(self.handle.as_ptr(), gain) } + } + fn set_max_gain(&mut self, gain: f32) { + unsafe { ffi::audio::sfSound_setMaxGain(self.handle.as_ptr(), gain) } + } + fn set_effect_processor(&mut self, effect_processor: super::sound_source::EffectProcessor) { + let (cb, user_data) = match effect_processor { + Some(cb) => { + let boxed = Box::new(cb); + let trampoline: unsafe extern "C" fn( + *const f32, + *mut c_uint, + *mut f32, + *mut c_uint, + c_uint, + *mut c_void, + ) = ffi::audio::effect_processor_trampoline; + (Some(trampoline), Box::into_raw(boxed).cast::()) + } + None => (None, std::ptr::null_mut()), + }; + + unsafe { + ffi::audio::sfSound_setEffectProcessor(self.handle.as_ptr(), cb, user_data); + } + } + fn pan(&self) -> f32 { + unsafe { ffi::audio::sfSound_getPan(self.handle.as_ptr()) } + } + fn is_spatialization_enabled(&self) -> bool { + unsafe { ffi::audio::sfSound_isSpatializationEnabled(self.handle.as_ptr()) } + } + fn direction(&self) -> Vector3f { + unsafe { ffi::audio::sfSound_getDirection(self.handle.as_ptr()) } + } + fn cone(&self) -> super::sound_source::Cone { + unsafe { ffi::audio::sfSound_getCone(self.handle.as_ptr()).into() } + } + fn velocity(&self) -> Vector3f { + unsafe { ffi::audio::sfSound_getVelocity(self.handle.as_ptr()) } + } + fn doppler_factor(&self) -> f32 { + unsafe { ffi::audio::sfSound_getDopplerFactor(self.handle.as_ptr()) } + } + fn directional_attenuation_factor(&self) -> f32 { + unsafe { ffi::audio::sfSound_getDirectionalAttenuationFactor(self.handle.as_ptr()) } + } + fn get_max_distance(&self) -> f32 { + unsafe { ffi::audio::sfSound_getMaxDistance(self.handle.as_ptr()) } + } + fn get_min_gain(&self) -> f32 { + unsafe { ffi::audio::sfSound_getMinGain(self.handle.as_ptr()) } + } + fn get_max_gain(&self) -> f32 { + unsafe { ffi::audio::sfSound_getMaxGain(self.handle.as_ptr()) } + } + fn status(&self) -> super::sound_source::Status { + unsafe { ffi::audio::sfSound_getStatus(self.handle.as_ptr()) } + } } impl Drop for Sound<'_> { diff --git a/src/audio/sound_buffer.rs b/src/audio/sound_buffer.rs index 23b19bf8..91dc7a89 100644 --- a/src/audio/sound_buffer.rs +++ b/src/audio/sound_buffer.rs @@ -1,7 +1,8 @@ use { + super::sound_channel::SoundChannel, crate::{ IntoSfResult, SfResult, - cpp::FBox, + cpp::{CppVector, FBox}, ffi::{self}, system::{InputStream, Time}, }, @@ -83,9 +84,10 @@ impl SoundBuffer { samples: &[i16], channel_count: u32, sample_rate: u32, + channel_map: &[SoundChannel], ) -> SfResult> { let mut new = Self::new()?; - new.load_from_samples(samples, channel_count, sample_rate)?; + new.load_from_samples(samples, channel_count, sample_rate, channel_map)?; Ok(new) } /// Load sound data from a file. @@ -119,6 +121,7 @@ impl SoundBuffer { samples: &[i16], channel_count: u32, sample_rate: u32, + channel_map: &[SoundChannel], ) -> SfResult<()> { unsafe { ffi::audio::sfSoundBuffer_loadFromSamples( @@ -127,6 +130,8 @@ impl SoundBuffer { samples.len() as _, channel_count, sample_rate, + channel_map.as_ptr().cast(), + channel_map.len(), ) } .into_sf_result() @@ -170,6 +175,17 @@ impl SoundBuffer { unsafe { ffi::audio::sfSoundBuffer_getChannelCount(self) } } + /// Get the map of position in sample frame to sound channel + /// + /// This is used to map a sample in the sample stream to a + /// position during spatialization. + /// + /// Return Map of position in sample frame to sound channel + #[must_use] + pub fn channel_map(&self) -> &'static CppVector { + unsafe { &*ffi::audio::sfSoundBuffer_getChannelMap(self) } + } + /// Get the total duration of a sound buffer /// /// Return the sound duration diff --git a/src/audio/sound_channel.rs b/src/audio/sound_channel.rs new file mode 100644 index 00000000..120621c1 --- /dev/null +++ b/src/audio/sound_channel.rs @@ -0,0 +1,53 @@ +use crate::{ + cpp::{CppVector, CppVectorItem}, + ffi::audio as ffi, +}; + +/// Types of sound channels that can be read/written form sound buffers/files +/// +/// In multi-channel audio, each sound channel can be +/// assigned a position. The position of the channel is +/// used to determine where to place a sound when it +/// is spatialized. Assigning an incorrect sound channel +/// will result in multi-channel audio being positioned +/// incorrectly when using spatialization. +#[repr(C)] +#[derive(Clone, Copy, PartialEq, Eq, Debug, Default)] +#[allow(missing_docs)] +pub enum SoundChannel { + #[default] + Unspecified, + Mono, + FrontLeft, + FrontRight, + FrontCenter, + FrontLeftOfCenter, + FrontRightOfCenter, + LowFrequencyEffects, + BackLeft, + BackRight, + BackCenter, + SideLeft, + SideRight, + TopCenter, + TopFrontLeft, + TopFrontRight, + TopFrontCenter, + TopBackLeft, + TopBackRight, + TopBackCenter, +} + +unsafe impl CppVectorItem for SoundChannel { + fn get_data(vec: &crate::cpp::CppVector) -> *const Self { + unsafe { ffi::sfSoundChannelVector_getData(vec) } + } + + fn get_len(vec: &CppVector) -> usize { + unsafe { ffi::sfSoundChannelVector_getLength(vec) } + } + + fn del(vec: &mut CppVector) { + unsafe { ffi::sfSoundChannelVector_del(vec) } + } +} diff --git a/src/audio/sound_source.rs b/src/audio/sound_source.rs index e284a591..ee3d9bc2 100644 --- a/src/audio/sound_source.rs +++ b/src/audio/sound_source.rs @@ -1,4 +1,123 @@ -use crate::system::Vector3f; +use crate::system::{Angle, Vector3f}; + +use std::f32::consts::PI; + +/// Structure defining the properties of a directional cone +/// +/// Sounds will play at gain 1 when they are positioned +/// within the inner angle of the cone. Sounds will play +/// at `outerGain` when they are positioned outside the +/// outer angle of the cone. The gain declines linearly +/// from 1 to `outerGain` as the sound moves from the inner +/// angle to the outer angle. +#[repr(C)] +#[derive(Debug, PartialEq, Clone, Copy)] +pub struct Cone { + /// Inner angle, in degrees + pub inner_angle: Angle, + /// Outer angle, in degrees + pub outer_angle: Angle, + /// Outer gain + pub outer_gain: f32, +} + +impl Default for Cone { + fn default() -> Self { + Self { + inner_angle: Angle::degrees(2. * PI), + outer_angle: Angle::degrees(2. * PI), + outer_gain: 1., + } + } +} + +/// Enumeration of statuses for sounds and musics +#[repr(C)] +#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] +pub enum Status { + /// Sound is not playing + #[default] + Stopped, + /// Sound is paused + Paused, + /// Sound is playing + Playing, +} + +/// Callable that is provided with sound data for processing +/// +/// When the audio engine sources sound data from sound +/// sources it will pass the data through an effects +/// processor if one is set. The sound data will already be +/// converted to the internal floating point format. +/// +/// Sound data that is processed this way is provided in +/// frames. Each frame contains 1 floating point sample per +/// channel. If e.g. the data source provides stereo data, +/// each frame will contain 2 floats. +/// +/// The effects processor function takes 4 parameters: +/// - The input data frames, channels interleaved +/// - The number of input data frames available +/// - The buffer to write output data frames to, channels interleaved +/// - The number of output data frames that the output buffer can hold +/// - The channel count +/// +/// The input and output frame counts are in/out parameters. +/// +/// When this function is called, the input count will +/// contain the number of frames available in the input +/// buffer. The output count will contain the size of the +/// output buffer i.e. the maximum number of frames that +/// can be written to the output buffer. +/// +/// Attempting to read more frames than the input frame +/// count or write more frames than the output frame count +/// will result in undefined behaviour. +/// +/// It is important to note that the channel count of the +/// audio engine currently sourcing data from this sound +/// will always be provided in `frameChannelCount`. This can +/// be different from the channel count of the sound source +/// so make sure to size necessary processing buffers +/// according to the engine channel count and not the sound +/// source channel count. +/// +/// When done processing the frames, the input and output +/// frame counts must be updated to reflect the actual +/// number of frames that were read from the input and +/// written to the output. +/// +/// The processing function should always try to process as +/// much sound data as possible i.e. always try to fill the +/// output buffer to the maximum. In certain situations for +/// specific effects it can be possible that the input frame +/// count and output frame count aren't equal. As long as +/// the frame counts are updated accordingly this is +/// perfectly valid. +/// +/// If the audio engine determines that no audio data is +/// available from the data source, the input data frames +/// pointer is set to `None` and the input frame count is +/// set to 0. In this case it is up to the function to +/// decide how to handle the situation. For specific effects +/// e.g. Echo/Delay buffered data might still be able to be +/// written to the output buffer even if there is no longer +/// any input data. +/// +/// An important thing to remember is that this function is +/// directly called by the audio engine. Because the audio +/// engine runs on an internal thread of its own, make sure +/// access to shared data is synchronized appropriately. +/// +/// Because this function is stored by the `SoundSource` +/// object it will be able to be called as long as the +/// `SoundSource` object hasn't yet been destroyed. Make sure +/// that any data this function references outlives the +/// `SoundSource` object otherwise use-after-free errors will +/// occur. +pub type EffectProcessor = + Option>; /// Base trait defining a sound's properties. pub trait SoundSource { @@ -13,6 +132,17 @@ pub trait SoundSource { /// pitch - New pitch to apply to the sound fn set_pitch(&mut self, pitch: f32); + /// Set the pan of the sound + /// + /// Using panning, a mono sound can be panned between + /// stereo channels. When the pan is set to -1, the sound + /// is played only on the left channel, when the pan is set + /// to +1, the sound is played only on the right channel. + /// + /// # Parameters + /// pan - New pan to apply to the sound [-1, +1] + fn set_pan(&mut self, pan: f32); + /// Set the volume of the sound. /// /// The volume is a value between 0 (mute) and 100 (full volume). @@ -22,6 +152,17 @@ pub trait SoundSource { /// volume - Volume of the sound fn set_volume(&mut self, volume: f32); + /// Set whether spatialization of the sound is enabled + /// + /// Spatialization is the application of various effects to + /// simulate a sound being emitted at a virtual position in + /// 3D space and exhibiting various physical phenomena such as + /// directional attenuation and doppler shift. + /// + /// # Parameters + /// enabled - `true` to enable spatialization, `false` to disable + fn set_spatialization_enabled(&mut self, enabled: bool); + /// Set the 3D position of the sound in the audio scene. /// /// Only sounds with one channel (mono sounds) can be spatialized. @@ -31,6 +172,57 @@ pub trait SoundSource { /// position - Position of the sound in the scene fn set_position>(&mut self, position: P); + /// The direction defines where the sound source is facing + /// in 3D space. It will affect how the sound is attenuated + /// if facing away from the listener. + /// The default direction of a sound is (0, 0, -1). + /// + /// # Parameters + /// direction - Direction of the sound in the scene + fn set_direction>(&mut self, direction: P); + + /// Set the cone properties of the sound in the audio scene + /// + /// The cone defines how directional attenuation is applied. + /// The default cone of a sound is (2 * PI, 2 * PI, 1). + /// + /// # Parameters + /// cone - Cone properties of the sound in the scene + fn set_cone(&mut self, cone: Cone); + + /// Set the 3D velocity of the sound in the audio scene + /// + /// The velocity is used to determine how to doppler shift + /// the sound. Sounds moving towards the listener will be + /// perceived to have a higher pitch and sounds moving away + /// from the listener will be perceived to have a lower pitch. + /// + /// # Parameters + /// velocity - Velocity of the sound in the scene + fn set_velocity>(&mut self, velocity: P); + + /// Set the doppler factor of the sound + /// + /// The doppler factor determines how strong the doppler + /// shift will be. + /// + /// # Parameters + /// factor - New doppler factor to apply to the sound + fn set_doppler_factor(&mut self, factor: f32); + + /// Set the directional attenuation factor of the sound + /// + /// Depending on the virtual position of an output channel + /// relative to the listener (such as in surround sound + /// setups), sounds will be attenuated when emitting them + /// from certain channels. This factor determines how strong + /// the attenuation based on output channel position + /// relative to the listener is. + /// + /// # Parameters + /// factor - New directional attenuation factor to apply to the sound + fn set_directional_attenuation_factor(&mut self, factor: f32); + /// Make the sound's position relative to the listener or absolute. /// /// Making a sound relative to the listener will ensure that it will always be played the @@ -53,6 +245,39 @@ pub trait SoundSource { /// distance - New minimum distance of the sound fn set_min_distance(&mut self, distance: f32); + /// Set the maximum distance of the sound + /// + /// The "maximum distance" of a sound is the minimum + /// distance at which it is heard at its minimum volume. Closer + /// than the maximum distance, it will start to fade in according + /// to its attenuation factor. + /// The default value of the maximum distance is the maximum + /// value a float can represent. + /// + /// # Parameters + /// distance - New maximum distance of the sound + fn set_max_distance(&mut self, distance: f32); + + /// Set the minimum gain of the sound + /// + /// When the sound is further away from the listener than + /// the "maximum distance" the attenuated gain is clamped + /// so it cannot go below the minimum gain value. + /// + /// # Parameters + /// gain - New minimum gain of the sound + fn set_min_gain(&mut self, gain: f32); + + /// Set the maximum gain of the sound + /// + /// When the sound is closer from the listener than + /// the "minimum distance" the attenuated gain is clamped + /// so it cannot go above the maximum gain value. + /// + /// # Parameters + /// gain - New maximum gain of the sound + fn set_max_gain(&mut self, gain: f32); + /// Set the attenuation factor of the sound. /// /// The attenuation is a multiplicative factor which makes the sound more or less loud @@ -66,23 +291,82 @@ pub trait SoundSource { /// attenuation - New attenuation factor of the sound fn set_attenuation(&mut self, attenuation: f32); + /// Set the effect processor to be applied to the sound + /// + /// The effect processor is a callable that will be called + /// with sound data to be processed. + /// + /// # Parameters + /// effectProcessor - The effect processor to attach to this sound, attach an empty processor to disable processing + fn set_effect_processor(&mut self, effect_processor: EffectProcessor); + /// Get the pitch of the sound. + #[must_use] fn pitch(&self) -> f32; + /// Get the pan of the sound + #[must_use] + fn pan(&self) -> f32; + /// Get the volume of the sound. /// /// Returns the volume of the sound, in the range [0, 100] + #[must_use] fn volume(&self) -> f32; + /// Returns whether spatialization of the sound is enabled + #[must_use] + fn is_spatialization_enabled(&self) -> bool; + /// Get the 3D position of the sound in the audio scene. + #[must_use] fn position(&self) -> Vector3f; + /// Get the 3D direction of the sound in the audio scene + #[must_use] + fn direction(&self) -> Vector3f; + + /// Get the cone properties of the sound in the audio scene + #[must_use] + fn cone(&self) -> Cone; + + /// Get the 3D velocity of the sound in the audio scene + #[must_use] + fn velocity(&self) -> Vector3f; + + /// Get the doppler factor of the sound + #[must_use] + fn doppler_factor(&self) -> f32; + + /// Get the directional attenuation factor of the sound + #[must_use] + fn directional_attenuation_factor(&self) -> f32; + /// Tell whether the sound's position is relative to the listener or is absolute. + #[must_use] fn is_relative_to_listener(&self) -> bool; /// Get the minimum distance of the sound. + #[must_use] fn min_distance(&self) -> f32; + ///Get the maximum distance of the sound + #[must_use] + fn get_max_distance(&self) -> f32; + + ///Get the minimum gain of the sound + #[must_use] + fn get_min_gain(&self) -> f32; + + ///Get the maximum gain of the sound + #[must_use] + fn get_max_gain(&self) -> f32; + /// Get the attenuation factor of the sound. + #[must_use] fn attenuation(&self) -> f32; + + /// Get the current status of a sound (stopped, paused, playing) + #[must_use] + fn status(&self) -> Status; } diff --git a/src/audio/sound_status.rs b/src/audio/sound_status.rs deleted file mode 100644 index 76ac5722..00000000 --- a/src/audio/sound_status.rs +++ /dev/null @@ -1,14 +0,0 @@ -use crate::ffi; -/// Enumeration of statuses for sounds and musics -#[repr(transparent)] -#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Copy)] -pub struct SoundStatus(pub(super) ffi::audio::sfSoundStatus); - -impl SoundStatus { - /// Sound is not playing. - pub const STOPPED: Self = Self(ffi::audio::sfSoundStatus::Stopped); - /// Sound is paused. - pub const PAUSED: Self = Self(ffi::audio::sfSoundStatus::Paused); - /// Sound is playing. - pub const PLAYING: Self = Self(ffi::audio::sfSoundStatus::Playing); -} diff --git a/src/audio/sound_stream.rs b/src/audio/sound_stream.rs index 2d3e2770..3651bdc7 100644 --- a/src/audio/sound_stream.rs +++ b/src/audio/sound_stream.rs @@ -1,10 +1,11 @@ use { + super::{sound_channel::SoundChannel, sound_source::SoundSource}, crate::{ - audio::{SoundSource, SoundStatus}, + cpp::CppVector, ffi::audio::*, system::{Time, Vector3f}, }, - std::{marker::PhantomData, os::raw::c_void, panic, ptr::NonNull}, + std::{ffi::c_uint, marker::PhantomData, os::raw::c_void, panic, ptr::NonNull}, }; /// Trait for streamed audio sources. @@ -23,6 +24,11 @@ pub trait SoundStream: Send { fn channel_count(&self) -> u32; /// Get the stream sample rate of the stream. fn sample_rate(&self) -> u32; + /// This is used to map a sample in the sample stream to a + /// position during spatialization. + /// + /// Return Map of position in sample frame to sound channel} + fn get_channel_map(&self) -> Vec; } /// Player for custom streamed audio sources. See [`SoundStream`]. @@ -81,6 +87,7 @@ impl<'a, S: SoundStream> SoundStreamPlayer<'a, S> { pub fn new(sound_stream: &'a mut S) -> Self { let channel_count = sound_stream.channel_count(); let sample_rate = sound_stream.sample_rate(); + let channel_map = sound_stream.get_channel_map(); let sound_stream: *mut S = sound_stream; Self { handle: unsafe { @@ -89,6 +96,8 @@ impl<'a, S: SoundStream> SoundStreamPlayer<'a, S> { Some(seek_callback::), channel_count, sample_rate, + channel_map.as_ptr().cast(), + channel_map.len(), sound_stream.cast(), )) .expect("Failed to create SoundStreamPlayer") @@ -112,11 +121,6 @@ impl<'a, S: SoundStream> SoundStreamPlayer<'a, S> { sfCustomSoundStream_pause(self.handle.as_ptr()); } } - /// Get the current status of the stream (stopped, paused, playing) - #[must_use] - pub fn status(&self) -> SoundStatus { - unsafe { SoundStatus(sfCustomSoundStream_getStatus(self.handle.as_ptr())) } - } /// Stop playing, lending out the underlying [`SoundStream`]. /// /// This function stops the stream if it was playing or paused, and does nothing if it was @@ -159,10 +163,18 @@ impl<'a, S: SoundStream> SoundStreamPlayer<'a, S> { pub fn sample_rate(&self) -> u32 { unsafe { sfCustomSoundStream_getSampleRate(self.handle.as_ptr()) } } + /// This is used to map a sample in the sample stream to a + /// position during spatialization. + /// + /// Return Map of position in sample frame to sound channel + #[must_use] + pub fn channel_map(&self) -> &'static CppVector { + unsafe { &*sfCustomSoundStream_getChannelMap(self.handle.as_ptr()) } + } /// Tell whether or not the stream is in loop mode. #[must_use] pub fn is_looping(&self) -> bool { - unsafe { sfCustomSoundStream_getLoop(self.handle.as_ptr()) } + unsafe { sfCustomSoundStream_isLooping(self.handle.as_ptr()) } } /// Set whether or not the stream should loop after reaching the end. /// @@ -170,7 +182,7 @@ impl<'a, S: SoundStream> SoundStreamPlayer<'a, S> { /// until it is stopped or `set_looping(false)` is called. /// The default looping state for streams is false. pub fn set_looping(&mut self, looping: bool) { - unsafe { sfCustomSoundStream_setLoop(self.handle.as_ptr(), looping) } + unsafe { sfCustomSoundStream_setLooping(self.handle.as_ptr(), looping) } } } @@ -211,6 +223,90 @@ impl SoundSource for SoundStreamPlayer<'_, S> { fn attenuation(&self) -> f32 { unsafe { sfCustomSoundStream_getAttenuation(self.handle.as_ptr()) } } + fn set_pan(&mut self, pan: f32) { + unsafe { sfCustomSoundStream_setPan(self.handle.as_ptr(), pan) } + } + fn set_spatialization_enabled(&mut self, enabled: bool) { + unsafe { sfCustomSoundStream_setSpatializationEnabled(self.handle.as_ptr(), enabled) } + } + fn set_direction>(&mut self, direction: P) { + unsafe { sfCustomSoundStream_setDirection(self.handle.as_ptr(), direction.into()) } + } + fn set_cone(&mut self, cone: super::sound_source::Cone) { + unsafe { sfCustomSoundStream_setCone(self.handle.as_ptr(), cone.into()) } + } + fn set_velocity>(&mut self, velocity: P) { + unsafe { sfCustomSoundStream_setVelocity(self.handle.as_ptr(), velocity.into()) } + } + fn set_doppler_factor(&mut self, factor: f32) { + unsafe { sfCustomSoundStream_setDopplerFactor(self.handle.as_ptr(), factor) } + } + fn set_directional_attenuation_factor(&mut self, factor: f32) { + unsafe { sfCustomSoundStream_setDirectionalAttenuationFactor(self.handle.as_ptr(), factor) } + } + fn set_max_distance(&mut self, distance: f32) { + unsafe { sfCustomSoundStream_setMaxDistance(self.handle.as_ptr(), distance) } + } + fn set_min_gain(&mut self, gain: f32) { + unsafe { sfCustomSoundStream_setMinGain(self.handle.as_ptr(), gain) } + } + fn set_max_gain(&mut self, gain: f32) { + unsafe { sfCustomSoundStream_setMaxGain(self.handle.as_ptr(), gain) } + } + fn set_effect_processor(&mut self, effect_processor: super::sound_source::EffectProcessor) { + let (cb, user_data) = match effect_processor { + Some(cb) => { + let boxed = Box::new(cb); + let trampoline: unsafe extern "C" fn( + *const f32, + *mut c_uint, + *mut f32, + *mut c_uint, + c_uint, + *mut c_void, + ) = effect_processor_trampoline; + (Some(trampoline), Box::into_raw(boxed).cast::()) + } + None => (None, std::ptr::null_mut()), + }; + + unsafe { + sfCustomSoundStream_setEffectProcessor(self.handle.as_ptr(), cb, user_data); + } + } + fn pan(&self) -> f32 { + unsafe { sfCustomSoundStream_getPan(self.handle.as_ptr()) } + } + fn is_spatialization_enabled(&self) -> bool { + unsafe { sfCustomSoundStream_isSpatializationEnabled(self.handle.as_ptr()) } + } + fn direction(&self) -> Vector3f { + unsafe { sfCustomSoundStream_getDirection(self.handle.as_ptr()) } + } + fn cone(&self) -> super::sound_source::Cone { + unsafe { sfCustomSoundStream_getCone(self.handle.as_ptr()).into() } + } + fn velocity(&self) -> Vector3f { + unsafe { sfCustomSoundStream_getVelocity(self.handle.as_ptr()) } + } + fn doppler_factor(&self) -> f32 { + unsafe { sfCustomSoundStream_getDopplerFactor(self.handle.as_ptr()) } + } + fn directional_attenuation_factor(&self) -> f32 { + unsafe { sfCustomSoundStream_getDirectionalAttenuationFactor(self.handle.as_ptr()) } + } + fn get_max_distance(&self) -> f32 { + unsafe { sfCustomSoundStream_getMaxDistance(self.handle.as_ptr()) } + } + fn get_min_gain(&self) -> f32 { + unsafe { sfCustomSoundStream_getMinGain(self.handle.as_ptr()) } + } + fn get_max_gain(&self) -> f32 { + unsafe { sfCustomSoundStream_getMaxGain(self.handle.as_ptr()) } + } + fn status(&self) -> super::sound_source::Status { + unsafe { sfCustomSoundStream_getStatus(self.handle.as_ptr()) } + } } impl Drop for SoundStreamPlayer<'_, S> { diff --git a/src/ffi/audio.rs b/src/ffi/audio.rs index 24c91ec1..2653a289 100644 --- a/src/ffi/audio.rs +++ b/src/ffi/audio.rs @@ -1,6 +1,11 @@ pub use crate::ffi::*; +use crate::{ + audio::{SoundChannel, sound_source}, + system::Angle, +}; use { super::system::sfInputStreamHelper, + crate::audio::listener, crate::cpp::{CppString as sfStdString, CppStringVector as sfStdStringVector}, }; @@ -13,6 +18,7 @@ decl_opaque! { } pub type sfSoundBuffer = crate::audio::SoundBuffer; +pub(crate) type sfSoundChannelVector = crate::cpp::CppVector; #[repr(C)] pub struct sfSoundStreamChunk { @@ -20,20 +26,6 @@ pub struct sfSoundStreamChunk { pub sample_count: usize, } -#[repr(C)] -#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] -pub enum sfSoundStatus { - /// Sound is not playing - Stopped, - /// Sound is paused - Paused, - /// Sound is playing - Playing, -} - -type sfMusicStatus = sfSoundStatus; -type sfSoundStreamStatus = sfSoundStatus; - #[repr(C)] pub struct sfTimeSpan { /// The beginning offset of the time range @@ -42,6 +34,112 @@ pub struct sfTimeSpan { pub length: i64, } +pub(crate) type sfEffectProcessor = Option< + unsafe extern "C" fn( + input_frames: *const f32, + input_frame_count: *mut c_uint, + output_frames: *mut f32, + output_frame_count: *mut c_uint, + frame_channel_count: c_uint, + user_data: *mut c_void, + ), +>; + +pub(crate) unsafe extern "C" fn effect_processor_trampoline( + input_frames: *const f32, + input_frame_count: *mut c_uint, + output_frames: *mut f32, + output_frame_count: *mut c_uint, + frame_channel_count: c_uint, + user_data: *mut c_void, +) { + unsafe { + let closure = &mut *user_data.cast::(); + + let in_frames = *input_frame_count as usize; + let out_frames = *output_frame_count as usize; + let channels = frame_channel_count as usize; + + let input = std::slice::from_raw_parts(input_frames, in_frames * channels); + let output = std::slice::from_raw_parts_mut(output_frames, out_frames * channels); + + if let Some(closure) = closure.as_mut() { + closure( + input, + output, + &mut *input_frame_count, + &mut *output_frame_count, + frame_channel_count, + ); + } + } +} + +#[repr(C)] +#[derive(Debug, Default, Clone, Copy, PartialEq)] +pub(crate) struct sfListenerCone { + /// Inner angle, in degrees + pub inner_angle: f32, + /// Outer angle, in degrees + pub outer_angle: f32, + /// Outer gain + pub outer_gain: f32, +} + +impl From for sfListenerCone { + #[inline] + fn from(cone: listener::Cone) -> Self { + sfListenerCone { + inner_angle: cone.inner_angle.as_degrees(), + outer_angle: cone.outer_angle.as_degrees(), + outer_gain: cone.outer_gain, + } + } +} + +impl From for listener::Cone { + fn from(cone: sfListenerCone) -> Self { + listener::Cone { + inner_angle: Angle::degrees(cone.inner_angle), + outer_angle: Angle::degrees(cone.outer_angle), + outer_gain: cone.outer_gain, + } + } +} + +#[repr(C)] +#[derive(Debug, Default, Clone, Copy, PartialEq)] +pub(crate) struct sfSoundSourceCone { + /// Inner angle, in degrees + pub inner_angle: f32, + /// Outer angle, in degrees + pub outer_angle: f32, + /// Outer gain + pub outer_gain: f32, +} + +impl From for sfSoundSourceCone { + fn from(cone: sound_source::Cone) -> Self { + sfSoundSourceCone { + inner_angle: cone.inner_angle.as_degrees(), + outer_angle: cone.outer_angle.as_degrees(), + outer_gain: cone.outer_gain, + } + } +} + +impl From for sound_source::Cone { + fn from(cone: sfSoundSourceCone) -> Self { + sound_source::Cone { + inner_angle: Angle::degrees(cone.inner_angle), + outer_angle: Angle::degrees(cone.outer_angle), + outer_gain: cone.outer_gain, + } + } +} + +type sfSoundChannel = SoundChannel; +type sfSoundStatus = sound_source::Status; type sfCustomSoundRecorderStartCb = Option bool>; type sfCustomSoundRecorderProcessCb = Option bool>; diff --git a/src/ffi/audio_bindgen.rs b/src/ffi/audio_bindgen.rs index 8c02066b..65a64064 100644 --- a/src/ffi/audio_bindgen.rs +++ b/src/ffi/audio_bindgen.rs @@ -9,36 +9,57 @@ pub fn sfCustomSoundRecorder_del(soundRecorder: *mut sfCustomSoundRecorder); pub fn sfCustomSoundRecorder_start(soundRecorder: *mut sfCustomSoundRecorder, sampleRate: c_uint) -> bool; pub fn sfCustomSoundRecorder_stop(soundRecorder: *mut sfCustomSoundRecorder); pub fn sfCustomSoundRecorder_getSampleRate(soundRecorder: *const sfCustomSoundRecorder) -> c_uint; -pub fn sfCustomSoundRecorder_setProcessingInterval(soundRecorder: *mut sfCustomSoundRecorder, interval: i64); pub fn sfCustomSoundRecorder_setDevice(soundRecorder: *mut sfCustomSoundRecorder, name: *const c_char) -> bool; pub fn sfCustomSoundRecorder_getDevice(soundRecorder: *mut sfCustomSoundRecorder) -> *const sfStdString; pub fn sfCustomSoundRecorder_setChannelCount(soundRecorder: *mut sfCustomSoundRecorder, channelCount: c_uint); pub fn sfCustomSoundRecorder_getChannelCount(soundRecorder: *const sfCustomSoundRecorder) -> c_uint; // CustomSoundStream.cpp -pub fn sfCustomSoundStream_new(onGetData: sfCustomSoundStreamGetDataCb, onSeek: sfCustomSoundStreamSeekCb, channelCount: c_uint, sampleRate: c_uint, userData: *mut c_void) -> *mut sfCustomSoundStream; -pub fn sfCustomSoundStream_del(soundStream: *mut sfCustomSoundStream); +pub fn sfCustomSoundStream_new(onGetData: sfCustomSoundStreamGetDataCb, onSeek: sfCustomSoundStreamSeekCb, channelCount: c_uint, sampleRate: c_uint, channelMap: *const sfSoundChannel, soundChannelMapLen: usize, userData: *mut c_void) -> *mut sfCustomSoundStream; pub fn sfCustomSoundStream_play(soundStream: *mut sfCustomSoundStream); pub fn sfCustomSoundStream_pause(soundStream: *mut sfCustomSoundStream); pub fn sfCustomSoundStream_stop(soundStream: *mut sfCustomSoundStream); -pub fn sfCustomSoundStream_getStatus(soundStream: *const sfCustomSoundStream) -> sfSoundStreamStatus; +pub fn sfCustomSoundStream_getStatus(soundStream: *const sfCustomSoundStream) -> sfSoundStatus; pub fn sfCustomSoundStream_getChannelCount(soundStream: *const sfCustomSoundStream) -> c_uint; pub fn sfCustomSoundStream_getSampleRate(soundStream: *const sfCustomSoundStream) -> c_uint; +pub fn sfCustomSoundStream_getChannelMap(soundStream: *const sfCustomSoundStream) -> *const sfSoundChannelVector; pub fn sfCustomSoundStream_setPitch(soundStream: *mut sfCustomSoundStream, pitch: f32); +pub fn sfCustomSoundStream_setPan(soundStream: *mut sfCustomSoundStream, pan: f32); pub fn sfCustomSoundStream_setVolume(soundStream: *mut sfCustomSoundStream, volume: f32); +pub fn sfCustomSoundStream_setSpatializationEnabled(soundStream: *mut sfCustomSoundStream, enabled: bool); pub fn sfCustomSoundStream_setPosition(soundStream: *mut sfCustomSoundStream, position: sfVector3f); +pub fn sfCustomSoundStream_setDirection(soundStream: *mut sfCustomSoundStream, position: sfVector3f); +pub fn sfCustomSoundStream_setCone(soundStream: *mut sfCustomSoundStream, cone: sfSoundSourceCone); +pub fn sfCustomSoundStream_setVelocity(soundStream: *mut sfCustomSoundStream, velocity: sfVector3f); +pub fn sfCustomSoundStream_setDopplerFactor(soundStream: *mut sfCustomSoundStream, factor: f32); +pub fn sfCustomSoundStream_setDirectionalAttenuationFactor(soundStream: *mut sfCustomSoundStream, factor: f32); pub fn sfCustomSoundStream_setRelativeToListener(soundStream: *mut sfCustomSoundStream, relative: bool); pub fn sfCustomSoundStream_setMinDistance(soundStream: *mut sfCustomSoundStream, distance: f32); +pub fn sfCustomSoundStream_setMaxDistance(soundStream: *mut sfCustomSoundStream, distance: f32); +pub fn sfCustomSoundStream_setMinGain(soundStream: *mut sfCustomSoundStream, gain: f32); +pub fn sfCustomSoundStream_setMaxGain(soundStream: *mut sfCustomSoundStream, gain: f32); pub fn sfCustomSoundStream_setAttenuation(soundStream: *mut sfCustomSoundStream, attenuation: f32); pub fn sfCustomSoundStream_setPlayingOffset(soundStream: *mut sfCustomSoundStream, timeOffset: i64); -pub fn sfCustomSoundStream_setLoop(soundStream: *mut sfCustomSoundStream, loop_: bool); +pub fn sfCustomSoundStream_setLooping(soundStream: *mut sfCustomSoundStream, loop_: bool); pub fn sfCustomSoundStream_getPitch(soundStream: *const sfCustomSoundStream) -> f32; +pub fn sfCustomSoundStream_getPan(soundStream: *const sfCustomSoundStream) -> f32; pub fn sfCustomSoundStream_getVolume(soundStream: *const sfCustomSoundStream) -> f32; +pub fn sfCustomSoundStream_isSpatializationEnabled(soundStream: *const sfCustomSoundStream) -> bool; pub fn sfCustomSoundStream_getPosition(soundStream: *const sfCustomSoundStream) -> sfVector3f; +pub fn sfCustomSoundStream_getDirection(soundStream: *const sfCustomSoundStream) -> sfVector3f; +pub fn sfCustomSoundStream_getCone(soundStream: *const sfCustomSoundStream) -> sfSoundSourceCone; +pub fn sfCustomSoundStream_getVelocity(soundStream: *const sfCustomSoundStream) -> sfVector3f; +pub fn sfCustomSoundStream_getDopplerFactor(soundStream: *const sfCustomSoundStream) -> f32; +pub fn sfCustomSoundStream_getDirectionalAttenuationFactor(soundStream: *const sfCustomSoundStream) -> f32; pub fn sfCustomSoundStream_isRelativeToListener(soundStream: *const sfCustomSoundStream) -> bool; pub fn sfCustomSoundStream_getMinDistance(soundStream: *const sfCustomSoundStream) -> f32; +pub fn sfCustomSoundStream_getMaxDistance(soundStream: *const sfCustomSoundStream) -> f32; +pub fn sfCustomSoundStream_getMinGain(soundStream: *const sfCustomSoundStream) -> f32; +pub fn sfCustomSoundStream_getMaxGain(soundStream: *const sfCustomSoundStream) -> f32; pub fn sfCustomSoundStream_getAttenuation(soundStream: *const sfCustomSoundStream) -> f32; -pub fn sfCustomSoundStream_getLoop(soundStream: *const sfCustomSoundStream) -> bool; +pub fn sfCustomSoundStream_isLooping(soundStream: *const sfCustomSoundStream) -> bool; pub fn sfCustomSoundStream_getPlayingOffset(soundStream: *const sfCustomSoundStream) -> i64; +pub fn sfCustomSoundStream_setEffectProcessor(soundStream: *mut sfCustomSoundStream, effectProcessor: sfEffectProcessor, userData: *mut c_void); +pub fn sfCustomSoundStream_del(music: *mut sfCustomSoundStream); // Listener.cpp pub fn sfListener_setGlobalVolume(volume: f32); pub fn sfListener_getGlobalVolume() -> f32; @@ -48,14 +69,17 @@ pub fn sfListener_setDirection(direction: sfVector3f); pub fn sfListener_getDirection() -> sfVector3f; pub fn sfListener_setUpVector(upVector: sfVector3f); pub fn sfListener_getUpVector() -> sfVector3f; +pub fn sfListener_setVelocity(velocity: sfVector3f); +pub fn sfListener_getVelocity() -> sfVector3f; +pub fn sfListener_setCone(cone: sfListenerCone); +pub fn sfListener_getCone() -> sfListenerCone; // Music.cpp pub fn sfMusic_new() -> *mut sfMusic; -pub fn sfMusic_del(music: *mut sfMusic); pub fn sfMusic_openFromFile(music: *mut sfMusic, filename: *const c_char) -> bool; pub fn sfMusic_openFromMemory(music: *mut sfMusic, data: *const u8, sizeInBytes: usize) -> bool; pub fn sfMusic_openFromStream(music: *mut sfMusic, stream: *mut sfInputStreamHelper) -> bool; -pub fn sfMusic_setLoop(music: *mut sfMusic, loop_: bool); -pub fn sfMusic_getLoop(music: *const sfMusic) -> bool; +pub fn sfMusic_setLooping(music: *mut sfMusic, loop_: bool); +pub fn sfMusic_isLooping(music: *const sfMusic) -> bool; pub fn sfMusic_getDuration(music: *const sfMusic) -> i64; pub fn sfMusic_getLoopPoints(music: *const sfMusic) -> sfTimeSpan; pub fn sfMusic_setLoopPoints(music: *mut sfMusic, timePoints: sfTimeSpan); @@ -64,47 +88,91 @@ pub fn sfMusic_pause(music: *mut sfMusic); pub fn sfMusic_stop(music: *mut sfMusic); pub fn sfMusic_getChannelCount(music: *const sfMusic) -> c_uint; pub fn sfMusic_getSampleRate(music: *const sfMusic) -> c_uint; -pub fn sfMusic_getStatus(music: *const sfMusic) -> sfMusicStatus; +pub fn sfMusic_getChannelMap(music: *const sfMusic) -> *const sfSoundChannelVector; +pub fn sfMusic_getStatus(music: *const sfMusic) -> sfSoundStatus; pub fn sfMusic_getPlayingOffset(music: *const sfMusic) -> i64; pub fn sfMusic_setPitch(music: *mut sfMusic, pitch: f32); +pub fn sfMusic_setPan(music: *mut sfMusic, pan: f32); pub fn sfMusic_setVolume(music: *mut sfMusic, volume: f32); +pub fn sfMusic_setSpatializationEnabled(music: *mut sfMusic, enabled: bool); +pub fn sfMusic_setDirection(music: *mut sfMusic, direction: sfVector3f); +pub fn sfMusic_setCone(music: *mut sfMusic, cone: sfSoundSourceCone); +pub fn sfMusic_setVelocity(music: *mut sfMusic, velocity: sfVector3f); +pub fn sfMusic_setDopplerFactor(music: *mut sfMusic, factor: f32); +pub fn sfMusic_setDirectionalAttenuationFactor(music: *mut sfMusic, factor: f32); pub fn sfMusic_setPosition(music: *mut sfMusic, position: sfVector3f); pub fn sfMusic_setRelativeToListener(music: *mut sfMusic, relative: bool); pub fn sfMusic_setMinDistance(music: *mut sfMusic, distance: f32); +pub fn sfMusic_setMaxDistance(music: *mut sfMusic, distance: f32); +pub fn sfMusic_setMinGain(music: *mut sfMusic, gain: f32); +pub fn sfMusic_setMaxGain(music: *mut sfMusic, gain: f32); pub fn sfMusic_setAttenuation(music: *mut sfMusic, attenuation: f32); pub fn sfMusic_setPlayingOffset(music: *mut sfMusic, timeOffset: i64); pub fn sfMusic_getPitch(music: *const sfMusic) -> f32; +pub fn sfMusic_getPan(music: *const sfMusic) -> f32; pub fn sfMusic_getVolume(music: *const sfMusic) -> f32; +pub fn sfMusic_isSpatializationEnabled(music: *const sfMusic) -> bool; pub fn sfMusic_getPosition(music: *const sfMusic) -> sfVector3f; +pub fn sfMusic_getDirection(music: *const sfMusic) -> sfVector3f; +pub fn sfMusic_getCone(music: *const sfMusic) -> sfSoundSourceCone; +pub fn sfMusic_getVelocity(music: *const sfMusic) -> sfVector3f; +pub fn sfMusic_getDopplerFactor(music: *const sfMusic) -> f32; +pub fn sfMusic_getDirectionalAttenuationFactor(music: *const sfMusic) -> f32; pub fn sfMusic_isRelativeToListener(music: *const sfMusic) -> bool; pub fn sfMusic_getMinDistance(music: *const sfMusic) -> f32; +pub fn sfMusic_getMaxDistance(music: *const sfMusic) -> f32; +pub fn sfMusic_getMinGain(music: *const sfMusic) -> f32; +pub fn sfMusic_getMaxGain(music: *const sfMusic) -> f32; pub fn sfMusic_getAttenuation(music: *const sfMusic) -> f32; +pub fn sfMusic_setEffectProcessor(music: *mut sfMusic, effectProcessor: sfEffectProcessor, userData: *mut c_void); +pub fn sfMusic_del(music: *mut sfMusic); // Sound.cpp -pub fn sfSound_new() -> *mut sfSound; +pub fn sfSound_new(buffer: *const sfSoundBuffer) -> *mut sfSound; pub fn sfSound_cpy(sound: *const sfSound) -> *mut sfSound; -pub fn sfSound_del(sound: *mut sfSound); pub fn sfSound_play(sound: *mut sfSound); pub fn sfSound_pause(sound: *mut sfSound); pub fn sfSound_stop(sound: *mut sfSound); pub fn sfSound_setBuffer(sound: *mut sfSound, buffer: *const sfSoundBuffer); pub fn sfSound_getBuffer(sound: *const sfSound) -> *const sfSoundBuffer; -pub fn sfSound_setLoop(sound: *mut sfSound, loop_: bool); -pub fn sfSound_getLoop(sound: *const sfSound) -> bool; +pub fn sfSound_setLooping(sound: *mut sfSound, loop_: bool); +pub fn sfSound_isLooping(sound: *const sfSound) -> bool; pub fn sfSound_getStatus(sound: *const sfSound) -> sfSoundStatus; pub fn sfSound_setPitch(sound: *mut sfSound, pitch: f32); +pub fn sfSound_setPan(sound: *mut sfSound, pan: f32); pub fn sfSound_setVolume(sound: *mut sfSound, volume: f32); +pub fn sfSound_setSpatializationEnabled(sound: *mut sfSound, enabled: bool); pub fn sfSound_setPosition(sound: *mut sfSound, position: sfVector3f); +pub fn sfSound_setDirection(sound: *mut sfSound, direction: sfVector3f); +pub fn sfSound_setCone(sound: *mut sfSound, cone: sfSoundSourceCone); +pub fn sfSound_setVelocity(sound: *mut sfSound, velocity: sfVector3f); +pub fn sfSound_setDopplerFactor(sound: *mut sfSound, factor: f32); +pub fn sfSound_setDirectionalAttenuationFactor(sound: *mut sfSound, factor: f32); pub fn sfSound_setRelativeToListener(sound: *mut sfSound, relative: bool); pub fn sfSound_setMinDistance(sound: *mut sfSound, distance: f32); +pub fn sfSound_setMaxDistance(sound: *mut sfSound, distance: f32); +pub fn sfSound_setMinGain(sound: *mut sfSound, gain: f32); +pub fn sfSound_setMaxGain(sound: *mut sfSound, gain: f32); pub fn sfSound_setAttenuation(sound: *mut sfSound, attenuation: f32); pub fn sfSound_setPlayingOffset(sound: *mut sfSound, timeOffset: i64); pub fn sfSound_getPitch(sound: *const sfSound) -> f32; +pub fn sfSound_getPan(sound: *const sfSound) -> f32; pub fn sfSound_getVolume(sound: *const sfSound) -> f32; +pub fn sfSound_isSpatializationEnabled(sound: *const sfSound) -> bool; pub fn sfSound_getPosition(sound: *const sfSound) -> sfVector3f; +pub fn sfSound_getDirection(sound: *const sfSound) -> sfVector3f; +pub fn sfSound_getCone(sound: *const sfSound) -> sfSoundSourceCone; +pub fn sfSound_getVelocity(sound: *const sfSound) -> sfVector3f; +pub fn sfSound_getDopplerFactor(sound: *const sfSound) -> f32; +pub fn sfSound_getDirectionalAttenuationFactor(sound: *const sfSound) -> f32; +pub fn sfSound_getMaxDistance(sound: *const sfSound) -> f32; +pub fn sfSound_getMinGain(sound: *const sfSound) -> f32; +pub fn sfSound_getMaxGain(sound: *const sfSound) -> f32; pub fn sfSound_isRelativeToListener(sound: *const sfSound) -> bool; pub fn sfSound_getMinDistance(sound: *const sfSound) -> f32; pub fn sfSound_getAttenuation(sound: *const sfSound) -> f32; pub fn sfSound_getPlayingOffset(sound: *const sfSound) -> i64; +pub fn sfSound_setEffectProcessor(sound: *mut sfSound, effectProcessor: sfEffectProcessor, userData: *mut c_void); +pub fn sfSound_del(music: *mut sfSound); // SoundBuffer.cpp pub fn sfSoundBuffer_new() -> *mut sfSoundBuffer; pub fn sfSoundBuffer_del(soundBuffer: *mut sfSoundBuffer); @@ -112,12 +180,13 @@ pub fn sfSoundBuffer_cpy(soundBuffer: *const sfSoundBuffer) -> *mut sfSoundBuffe pub fn sfSoundBuffer_loadFromFile(buffer: *mut sfSoundBuffer, filename: *const c_char) -> bool; pub fn sfSoundBuffer_loadFromMemory(buffer: *mut sfSoundBuffer, data: *const u8, sizeInBytes: usize) -> bool; pub fn sfSoundBuffer_loadFromStream(buffer: *mut sfSoundBuffer, stream: *mut sfInputStreamHelper) -> bool; -pub fn sfSoundBuffer_loadFromSamples(buffer: *mut sfSoundBuffer, samples: *const i16, sampleCount: u64, channelCount: c_uint, sampleRate: c_uint) -> bool; +pub fn sfSoundBuffer_loadFromSamples(buffer: *mut sfSoundBuffer, samples: *const i16, sampleCount: u64, channelCount: c_uint, sampleRate: c_uint, channelMap: *const sfSoundChannel, channelMapLen: usize) -> bool; pub fn sfSoundBuffer_saveToFile(soundBuffer: *const sfSoundBuffer, filename: *const c_char) -> bool; pub fn sfSoundBuffer_getSamples(soundBuffer: *const sfSoundBuffer) -> *const i16; pub fn sfSoundBuffer_getSampleCount(soundBuffer: *const sfSoundBuffer) -> u64; pub fn sfSoundBuffer_getSampleRate(soundBuffer: *const sfSoundBuffer) -> c_uint; pub fn sfSoundBuffer_getChannelCount(soundBuffer: *const sfSoundBuffer) -> c_uint; +pub fn sfSoundBuffer_getChannelMap(soundStream: *const sfSoundBuffer) -> *const sfSoundChannelVector; pub fn sfSoundBuffer_getDuration(soundBuffer: *const sfSoundBuffer) -> i64; // SoundBufferRecorder.cpp pub fn sfSoundBufferRecorder_new() -> *mut sfSoundBufferRecorder; @@ -128,6 +197,12 @@ pub fn sfSoundBufferRecorder_getSampleRate(soundBufferRecorder: *const sfSoundBu pub fn sfSoundBufferRecorder_getBuffer(soundBufferRecorder: *const sfSoundBufferRecorder) -> *const sfSoundBuffer; pub fn sfSoundBufferRecorder_setDevice(soundBufferRecorder: *mut sfSoundBufferRecorder, name: *const c_char) -> bool; pub fn sfSoundBufferRecorder_getDevice(soundBufferRecorder: *mut sfSoundBufferRecorder) -> *const sfStdString; +pub fn sfSoundBufferRecorder_setChannelCount(soundBufferRecorder: *mut sfSoundBufferRecorder, channelCount: c_uint); +pub fn sfSoundBufferRecorder_getChannelCount(soundBufferRecorder: *const sfSoundBufferRecorder) -> c_uint; +// SoundChannel.cpp +pub fn sfSoundChannelVector_getLength(vec: *const sfSoundChannelVector) -> usize; +pub fn sfSoundChannelVector_getData(vec: *const sfSoundChannelVector) -> *const sfSoundChannel; +pub fn sfSoundChannelVector_del(vec: *const sfSoundChannelVector); // SoundRecorder.cpp pub fn sfSoundRecorder_isAvailable() -> bool; pub fn sfSoundRecorder_getDefaultDevice() -> *mut sfStdString; diff --git a/src/ffi/graphics.rs b/src/ffi/graphics.rs index f1bb9f20..ff435aa8 100644 --- a/src/ffi/graphics.rs +++ b/src/ffi/graphics.rs @@ -1,3 +1,4 @@ +use crate::ffi::system::sfBuffer; pub use crate::ffi::*; use { super::system::sfInputStreamHelper, @@ -27,6 +28,7 @@ type sfImage = crate::graphics::Image; type sfRenderWindow = crate::graphics::RenderWindow; type sfRenderTexture = crate::graphics::RenderTexture; type sfVertexBuffer = crate::graphics::VertexBuffer; +pub(crate) type sfState = crate::window::window_enums::State; /// Enumeration of the blending factors. /// @@ -70,6 +72,10 @@ pub enum BlendEquation { Subtract, /// `pixel = dst * dst_factor - src * src_factor` ReverseSubtract, + /// `pixel = min(Dst, Src)` + Min, + /// `pixel = max(Dst, Src)` + Max, } /// Blending modes for drawing. @@ -135,6 +141,104 @@ pub struct BlendMode { pub alpha_equation: BlendEquation, } +/// Enumeration of the stencil test comparisons that can be performed +/// The comparisons are mapped directly to their OpenGL equivalents, +/// specified by `glStencilFunc()`. +#[allow(dead_code)] +#[repr(C)] +#[derive(Clone, Copy, Default, Debug, PartialEq, Eq)] +pub enum StencilComparison { + /// The stencil test never passes + Never, + /// The stencil test passes if the new value is less than the value in the stencil buffer + Less, + /// The stencil test passes if the new value is less than or equal to the value in the stencil buffer + LessEqual, + /// The stencil test passes if the new value is greater than the value in the stencil buffer + Greater, + /// The stencil test passes if the new value is greater than or equal to the value in the stencil buffer + GreaterEqual, + /// The stencil test passes if the new value is strictly equal to the value in the stencil buffer + Equal, + /// The stencil test passes if the new value is strictly unequal to the value in the stencil buffer + NotEqual, + /// The stencil test always passes + #[default] + Always, +} + +/// Enumeration of the stencil buffer update operations +/// +/// The update operations are mapped directly to their OpenGL equivalents, +/// specified by `glStencilOp()`. +#[allow(dead_code)] +#[repr(C)] +#[derive(Clone, Copy, Default, Debug, PartialEq, Eq)] +pub enum StencilUpdateOperation { + /// If the stencil test passes, the value in the stencil buffer is not modified + #[default] + Keep, + /// If the stencil test passes, the value in the stencil buffer is set to zero + Zero, + /// If the stencil test passes, the value in the stencil buffer is set to the new value + Replace, + /// If the stencil test passes, the value in the stencil buffer is incremented and if required clamped + Increment, + /// If the stencil test passes, the value in the stencil buffer is decremented and if required clamped + Decrement, + /// If the stencil test passes, the value in the stencil buffer is bitwise inverted + Invert, +} + +/// Stencil value type (also used as a mask) +#[repr(C)] +#[derive(Clone, Copy, Default, Debug, PartialEq, Eq)] +pub struct StencilValue { + /// The stored stencil value + value: u32, +} + +/// Stencil modes for drawing +#[repr(C)] +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub struct StencilMode { + /// The comparison we're performing the stencil test with + comparison: StencilComparison, + /// The update operation to perform if the stencil test passes + update_operation: StencilUpdateOperation, + /// The reference value we're performing the stencil test with + reference: StencilValue, + /// The mask to apply to both the reference value and the value in the stencil buffer + mask: StencilValue, + /// Whether we should update the color buffer in addition to the stencil buffer + only: bool, +} + +impl StencilMode { + pub const DEFAULT: Self = Self { + comparison: StencilComparison::Always, + update_operation: StencilUpdateOperation::Keep, + reference: StencilValue { value: 0 }, + mask: StencilValue { value: u32::MAX }, + only: false, + }; +} + +impl Default for StencilMode { + fn default() -> Self { + Self::DEFAULT + } +} +/// Types of texture coordinates that can be used for rendering. +#[repr(C)] +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub enum CoordinateType { + /// Texture coordinates in range [0 .. 1]. + sfCoordinateTypeNormalized, + /// Texture coordinates in range [0 .. size]. + sfCoordinateTypePixels, +} + /// Types of shaders #[repr(C)] #[derive(Debug, Clone, Copy, PartialEq, Eq)] @@ -271,10 +375,9 @@ pub enum sfPrimitiveType { TriangleStrip, /// List of connected triangles, a point uses the common center and the previous point to form a triangle TriangleFan, - /// List of individual quads - Quads, } type sfColor = Color; +type sfStencilValue = StencilValue; include!("graphics_bindgen.rs"); diff --git a/src/ffi/graphics_bindgen.rs b/src/ffi/graphics_bindgen.rs index f845e860..dc3a729d 100644 --- a/src/ffi/graphics_bindgen.rs +++ b/src/ffi/graphics_bindgen.rs @@ -32,6 +32,7 @@ pub fn sfCircleShape_getOutlineColor(shape: *const sfCircleShape) -> sfColor; pub fn sfCircleShape_getOutlineThickness(shape: *const sfCircleShape) -> f32; pub fn sfCircleShape_getPointCount(shape: *const sfCircleShape) -> usize; pub fn sfCircleShape_getPoint(shape: *const sfCircleShape, index: usize) -> sfVector2f; +pub fn sfCircleShape_getGeometricCenter(shape: *const sfCircleShape) -> sfVector2f; pub fn sfCircleShape_setRadius(shape: *mut sfCircleShape, radius: f32); pub fn sfCircleShape_getRadius(shape: *const sfCircleShape) -> f32; pub fn sfCircleShape_setPointCount(shape: *mut sfCircleShape, count: usize); @@ -66,6 +67,7 @@ pub fn sfConvexShape_getOutlineColor(shape: *const sfConvexShape) -> sfColor; pub fn sfConvexShape_getOutlineThickness(shape: *const sfConvexShape) -> f32; pub fn sfConvexShape_getPointCount(shape: *const sfConvexShape) -> usize; pub fn sfConvexShape_getPoint(shape: *const sfConvexShape, index: usize) -> sfVector2f; +pub fn sfConvexShape_getGeometricCenter(shape: *const sfConvexShape) -> sfVector2f; pub fn sfConvexShape_setPointCount(shape: *mut sfConvexShape, count: usize); pub fn sfConvexShape_setPoint(shape: *mut sfConvexShape, index: usize, point: sfVector2f); pub fn sfConvexShape_getLocalBounds(shape: *const sfConvexShape) -> sfFloatRect; @@ -97,6 +99,7 @@ pub fn sfCustomShape_getFillColor(shape: *const sfCustomShape) -> sfColor; pub fn sfCustomShape_getOutlineColor(shape: *const sfCustomShape) -> sfColor; pub fn sfCustomShape_getOutlineThickness(shape: *const sfCustomShape) -> f32; pub fn sfCustomShape_getPointCount(shape: *const sfCustomShape) -> usize; +pub fn sfCustomShape_getGeometricCenter(shape: *const sfCustomShape) -> sfVector2f; pub fn sfCustomShape_getPoint(shape: *const sfCustomShape, index: usize) -> sfVector2f; pub fn sfCustomShape_getLocalBounds(shape: *const sfCustomShape) -> sfFloatRect; pub fn sfCustomShape_getGlobalBounds(shape: *const sfCustomShape) -> sfFloatRect; @@ -105,10 +108,11 @@ pub fn sfCustomShape_update(shape: *mut sfCustomShape); pub fn sfFont_new() -> *mut sfFont; pub fn sfFont_del(font: *mut sfFont); pub fn sfFont_cpy(font: *const sfFont) -> *mut sfFont; -pub fn sfFont_loadFromFile(font: *mut sfFont, filename: *const c_char) -> bool; -pub fn sfFont_loadFromMemory(font: *mut sfFont, data: *const u8, sizeInBytes: usize) -> bool; -pub fn sfFont_loadFromStream(font: *mut sfFont, stream: *mut sfInputStreamHelper) -> bool; +pub fn sfFont_openFromFile(font: *mut sfFont, filename: *const c_char) -> bool; +pub fn sfFont_openFromMemory(font: *mut sfFont, data: *const u8, sizeInBytes: usize) -> bool; +pub fn sfFont_openFromStream(font: *mut sfFont, stream: *mut sfInputStreamHelper) -> bool; pub fn sfFont_getGlyph(font: *const sfFont, codePoint: u32, characterSize: c_uint, bold: bool, outlineThickness: f32) -> sfGlyph; +pub fn sfFont_hasGlyph(font: *const sfFont, codePoint: u32) -> bool; pub fn sfFont_getKerning(font: *const sfFont, first: u32, second: u32, characterSize: c_uint) -> f32; pub fn sfFont_getBoldKerning(font: *const sfFont, first: u32, second: u32, characterSize: c_uint) -> f32; pub fn sfFont_getLineSpacing(font: *const sfFont, characterSize: c_uint) -> f32; @@ -122,16 +126,17 @@ pub fn sfFont_getInfo(font: *const sfFont) -> sfFontInfo; pub fn sfImage_new() -> *mut sfImage; pub fn sfImage_cpy(image: *const sfImage) -> *mut sfImage; pub fn sfImage_del(image: *mut sfImage); -pub fn sfImage_create_w_h_color(image: *mut sfImage, width: c_uint, height: c_uint, color: sfColor); -pub fn sfImage_create_w_h_pixels(image: *mut sfImage, width: c_uint, height: c_uint, data: *const u8); +pub fn sfImage_resizeWithColor(image: *mut sfImage, size: sfVector2u, color: sfColor); +pub fn sfImage_resizeWithPixels(image: *mut sfImage, size: sfVector2u, pixels: *const u8); pub fn sfImage_loadFromFile(image: *mut sfImage, filename: *const c_char) -> bool; pub fn sfImage_loadFromMemory(image: *mut sfImage, data: *const u8, sizeInBytes: usize) -> bool; pub fn sfImage_loadFromStream(image: *mut sfImage, stream: *mut sfInputStreamHelper) -> bool; pub fn sfImage_saveToFile(image: *const sfImage, filename: *const c_char) -> bool; +pub fn sfImage_saveToMemory(image: *const sfImage, format: *const c_char) -> *mut sfBuffer; pub fn sfImage_createMaskFromColor(image: *mut sfImage, colorKey: sfColor, alpha: u8); -pub fn sfImage_copy(image: *mut sfImage, source: *const sfImage, destX: c_uint, destY: c_uint, sourceRect: sfIntRect, applyAlpha: bool); -pub fn sfImage_setPixel(image: *mut sfImage, x: c_uint, y: c_uint, color: sfColor); -pub fn sfImage_getPixel(image: *const sfImage, x: c_uint, y: c_uint) -> sfColor; +pub fn sfImage_copy(image: *mut sfImage, source: *const sfImage, dest: sfVector2u, sourceRect: sfIntRect, applyAlpha: bool) -> bool; +pub fn sfImage_setPixel(image: *mut sfImage, coords: sfVector2u, color: sfColor); +pub fn sfImage_getPixel(image: *const sfImage, coords: sfVector2u) -> sfColor; pub fn sfImage_getPixelsPtr(image: *const sfImage) -> *const u8; pub fn sfImage_getSize(image: *const sfImage) -> sfVector2u; pub fn sfImage_flipHorizontally(image: *mut sfImage); @@ -165,6 +170,7 @@ pub fn sfRectangleShape_getOutlineColor(shape: *const sfRectangleShape) -> sfCol pub fn sfRectangleShape_getOutlineThickness(shape: *const sfRectangleShape) -> f32; pub fn sfRectangleShape_getPointCount(shape: *const sfRectangleShape) -> usize; pub fn sfRectangleShape_getPoint(shape: *const sfRectangleShape, index: usize) -> sfVector2f; +pub fn sfRectangleShape_getGeometricCenter(shape: *const sfRectangleShape) -> sfVector2f; pub fn sfRectangleShape_setSize(shape: *mut sfRectangleShape, size: sfVector2f); pub fn sfRectangleShape_getSize(shape: *const sfRectangleShape) -> sfVector2f; pub fn sfRectangleShape_getLocalBounds(shape: *const sfRectangleShape) -> sfFloatRect; @@ -172,16 +178,19 @@ pub fn sfRectangleShape_getGlobalBounds(shape: *const sfRectangleShape) -> sfFlo // RenderTexture.cpp pub fn sfRenderTexture_new() -> *mut sfRenderTexture; pub fn sfRenderTexture_del(renderTexture: *mut sfRenderTexture); -pub fn sfRenderTexture_create(renderTexture: *mut sfRenderTexture, width: c_uint, height: c_uint, settings: *const sfContextSettings) -> bool; +pub fn sfRenderTexture_resize(texture: *mut sfRenderTexture, size: sfVector2u, settings: *const sfContextSettings) -> bool; pub fn sfRenderTexture_getSize(renderTexture: *const sfRenderTexture) -> sfVector2u; pub fn sfRenderTexture_isSrgb(renderTexture: *const sfRenderTexture) -> bool; pub fn sfRenderTexture_setActive(renderTexture: *mut sfRenderTexture, active: bool) -> bool; pub fn sfRenderTexture_display(renderTexture: *mut sfRenderTexture); pub fn sfRenderTexture_clear(renderTexture: *mut sfRenderTexture, color: sfColor); +pub fn sfRenderTexture_clearStencil(renderTexture: *mut sfRenderTexture, stencilValue: sfStencilValue); +pub fn sfRenderTexture_clearColorAndStencil(renderTexture: *mut sfRenderTexture, color: sfColor, stencilValue: sfStencilValue); pub fn sfRenderTexture_setView(renderTexture: *mut sfRenderTexture, view: *const sfView); pub fn sfRenderTexture_getView(renderTexture: *const sfRenderTexture) -> *const sfView; pub fn sfRenderTexture_getDefaultView(renderTexture: *const sfRenderTexture) -> *const sfView; pub fn sfRenderTexture_getViewport(renderTexture: *const sfRenderTexture, view: *const sfView) -> sfIntRect; +pub fn sfRenderTexture_getScissor(renderTexture: *const sfRenderTexture, view: *const sfView) -> sfIntRect; pub fn sfRenderTexture_mapPixelToCoords(renderTexture: *const sfRenderTexture, point: sfVector2i) -> sfVector2f; pub fn sfRenderTexture_mapPixelToCoords_View(renderTexture: *const sfRenderTexture, point: sfVector2i, targetView: *const sfView) -> sfVector2f; pub fn sfRenderTexture_mapCoordsToPixel(renderTexture: *const sfRenderTexture, point: sfVector2f) -> sfVector2i; @@ -205,22 +214,23 @@ pub fn sfRenderTexture_setRepeated(renderTexture: *mut sfRenderTexture, repeated pub fn sfRenderTexture_isRepeated(renderTexture: *const sfRenderTexture) -> bool; pub fn sfRenderTexture_generateMipmap(renderTexture: *mut sfRenderTexture) -> bool; // RenderWindow.cpp -pub fn sfRenderWindow_new_mtss(mode: sfVideoMode, title: *const u32, style: u32, settings: *const sfContextSettings) -> *mut sfRenderWindow; +pub fn sfRenderWindow_new_mtsss(mode: sfVideoMode, title: *const u32, style: u32, state: sfState, settings: *const sfContextSettings) -> *mut sfRenderWindow; pub fn sfRenderWindow_new_handle_settings(handle: sfWindowHandle, settings: *const sfContextSettings) -> *mut sfRenderWindow; pub fn sfRenderWindow_del(renderWindow: *mut sfRenderWindow); -pub fn sfRenderWindow_create_mtss(renderWindow: *mut sfRenderWindow, mode: sfVideoMode, title: *const u32, style: u32, settings: *const sfContextSettings); pub fn sfRenderWindow_close(renderWindow: *mut sfRenderWindow); pub fn sfRenderWindow_isOpen(renderWindow: *const sfRenderWindow) -> bool; pub fn sfRenderWindow_getSettings(renderWindow: *const sfRenderWindow) -> *const sfContextSettings; pub fn sfRenderWindow_pollEvent(renderWindow: *mut sfRenderWindow, event: *mut sfEvent) -> bool; -pub fn sfRenderWindow_waitEvent(renderWindow: *mut sfRenderWindow, event: *mut sfEvent) -> bool; +pub fn sfRenderWindow_waitEvent(renderWindow: *mut sfRenderWindow, event: *mut sfEvent, timeout: i64) -> bool; pub fn sfRenderWindow_getPosition(renderWindow: *const sfRenderWindow) -> sfVector2i; pub fn sfRenderWindow_setPosition(renderWindow: *mut sfRenderWindow, position: sfVector2i); pub fn sfRenderWindow_getSize(renderWindow: *const sfRenderWindow) -> sfVector2u; pub fn sfRenderWindow_setSize(renderWindow: *mut sfRenderWindow, size: sfVector2u); +pub fn sfRenderWindow_setMinimumSize(renderWindow: *mut sfRenderWindow, size: *const sfVector2u); +pub fn sfRenderWindow_setMaximumSize(renderWindow: *mut sfRenderWindow, size: *const sfVector2u); pub fn sfRenderWindow_isSrgb(renderWindow: *const sfRenderWindow) -> bool; pub fn sfRenderWindow_setUnicodeTitle(renderWindow: *mut sfRenderWindow, title: *const u32); -pub fn sfRenderWindow_setIcon(renderWindow: *mut sfRenderWindow, width: c_uint, height: c_uint, pixels: *const u8); +pub fn sfRenderWindow_setIcon(renderWindow: *mut sfRenderWindow, size: sfVector2u, pixels: *const u8); pub fn sfRenderWindow_setVisible(renderWindow: *mut sfRenderWindow, visible: bool); pub fn sfRenderWindow_setVerticalSyncEnabled(renderWindow: *mut sfRenderWindow, enabled: bool); pub fn sfRenderWindow_setMouseCursorVisible(renderWindow: *mut sfRenderWindow, visible: bool); @@ -233,12 +243,15 @@ pub fn sfRenderWindow_hasFocus(renderWindow: *const sfRenderWindow) -> bool; pub fn sfRenderWindow_display(renderWindow: *mut sfRenderWindow); pub fn sfRenderWindow_setFramerateLimit(renderWindow: *mut sfRenderWindow, limit: c_uint); pub fn sfRenderWindow_setJoystickThreshold(renderWindow: *mut sfRenderWindow, threshold: f32); -pub fn sfRenderWindow_getSystemHandle(renderWindow: *const sfRenderWindow) -> sfWindowHandle; +pub fn sfRenderWindow_getNativeHandle(renderWindow: *const sfRenderWindow) -> sfWindowHandle; pub fn sfRenderWindow_clear(renderWindow: *mut sfRenderWindow, color: sfColor); +pub fn sfRenderWindow_clearStencil(renderWindow: *mut sfRenderWindow, stencilValue: sfStencilValue); +pub fn sfRenderWindow_clearColorAndStencil(renderWindow: *mut sfRenderWindow, color: sfColor, stencilValue: sfStencilValue); pub fn sfRenderWindow_setView(renderWindow: *mut sfRenderWindow, view: *const sfView); pub fn sfRenderWindow_getView(renderWindow: *const sfRenderWindow) -> *const sfView; pub fn sfRenderWindow_getDefaultView(renderWindow: *const sfRenderWindow) -> *const sfView; pub fn sfRenderWindow_getViewport(renderWindow: *const sfRenderWindow, view: *const sfView) -> sfIntRect; +pub fn sfRenderWindow_getScissor(renderWindow: *const sfRenderWindow, view: *const sfView) -> sfIntRect; pub fn sfRenderWindow_mapPixelToCoords(renderWindow: *const sfRenderWindow, point: sfVector2i) -> sfVector2f; pub fn sfRenderWindow_mapPixelToCoords_View(renderWindow: *const sfRenderWindow, point: sfVector2i, targetView: *const sfView) -> sfVector2f; pub fn sfRenderWindow_mapCoordsToPixel(renderWindow: *const sfRenderWindow, point: sfVector2f) -> sfVector2i; @@ -296,7 +309,7 @@ pub fn sfShader_bind(shader: *const sfShader); pub fn sfShader_isAvailable() -> bool; pub fn sfShader_isGeometryAvailable() -> bool; // Sprite.cpp -pub fn sfSprite_new() -> *mut sfSprite; +pub fn sfSprite_new(texture: *const sfTexture, rect: sfIntRect) -> *mut sfSprite; pub fn sfSprite_cpy(sprite: *const sfSprite) -> *mut sfSprite; pub fn sfSprite_del(sprite: *mut sfSprite); pub fn sfSprite_setPosition(sprite: *mut sfSprite, position: sfVector2f); @@ -313,7 +326,7 @@ pub fn sfSprite_scale(sprite: *mut sfSprite, factors: sfVector2f); pub fn sfSprite_getTransform(sprite: *const sfSprite) -> *const sfTransform; pub fn sfSprite_getInverseTransform(sprite: *const sfSprite) -> *const sfTransform; pub fn sfSprite_setTexture(sprite: *mut sfSprite, texture: *const sfTexture, resetRect: bool); -pub fn sfSprite_setTextureRect(sprite: *mut sfSprite, rectangle: sfIntRect); +pub fn sfSprite_setTextureRect(sprite: *mut sfSprite, rect: sfIntRect); pub fn sfSprite_setColor(sprite: *mut sfSprite, color: sfColor); pub fn sfSprite_getTexture(sprite: *const sfSprite) -> *const sfTexture; pub fn sfSprite_getTextureRect(sprite: *const sfSprite) -> sfIntRect; @@ -321,7 +334,7 @@ pub fn sfSprite_getColor(sprite: *const sfSprite) -> sfColor; pub fn sfSprite_getLocalBounds(sprite: *const sfSprite) -> sfFloatRect; pub fn sfSprite_getGlobalBounds(sprite: *const sfSprite) -> sfFloatRect; // Text.cpp -pub fn sfText_new() -> *mut sfText; +pub fn sfText_new(font: *const sfFont, string: *const u32, size: c_uint) -> *mut sfText; pub fn sfText_cpy(text: *const sfText) -> *mut sfText; pub fn sfText_del(text: *mut sfText); pub fn sfText_setPosition(text: *mut sfText, position: sfVector2f); @@ -362,21 +375,20 @@ pub fn sfText_getGlobalBounds(text: *const sfText) -> sfFloatRect; pub fn sfTexture_new() -> *mut sfTexture; pub fn sfTexture_cpy(texture: *const sfTexture) -> *mut sfTexture; pub fn sfTexture_del(texture: *mut sfTexture); -pub fn sfTexture_create(tex: *mut sfTexture, width: c_uint, height: c_uint) -> bool; -pub fn sfTexture_loadFromFile(tex: *mut sfTexture, filename: *const c_char, area: sfIntRect) -> bool; -pub fn sfTexture_loadFromMemory(tex: *mut sfTexture, data: *const c_void, sizeInBytes: usize, area: sfIntRect) -> bool; -pub fn sfTexture_loadFromStream(tex: *mut sfTexture, stream: *mut sfInputStreamHelper, area: sfIntRect) -> bool; -pub fn sfTexture_loadFromImage(tex: *mut sfTexture, image: *const sfImage, area: sfIntRect) -> bool; +pub fn sfTexture_resize(texture: *mut sfTexture, size: sfVector2u, sRgb: bool) -> bool; +pub fn sfTexture_loadFromFile(tex: *mut sfTexture, filename: *const c_char, sRgb: bool, area: sfIntRect) -> bool; +pub fn sfTexture_loadFromMemory(tex: *mut sfTexture, data: *const c_void, sizeInBytes: usize, sRgb: bool, area: sfIntRect) -> bool; +pub fn sfTexture_loadFromStream(tex: *mut sfTexture, stream: *mut sfInputStreamHelper, sRgb: bool, area: sfIntRect) -> bool; +pub fn sfTexture_loadFromImage(tex: *mut sfTexture, image: *const sfImage, sRgb: bool, area: sfIntRect) -> bool; pub fn sfTexture_getSize(texture: *const sfTexture) -> sfVector2u; pub fn sfTexture_copyToImage(texture: *const sfTexture) -> *mut sfImage; -pub fn sfTexture_updateFromPixels(texture: *mut sfTexture, pixels: *const u8, width: c_uint, height: c_uint, x: c_uint, y: c_uint); -pub fn sfTexture_updateFromTexture(destination: *mut sfTexture, texture: *const sfTexture, x: c_uint, y: c_uint); -pub fn sfTexture_updateFromImage(texture: *mut sfTexture, image: *const sfImage, x: c_uint, y: c_uint); -pub fn sfTexture_updateFromWindow(texture: *mut sfTexture, window: *const sfWindow, x: c_uint, y: c_uint); -pub fn sfTexture_updateFromRenderWindow(texture: *mut sfTexture, renderWindow: *const sfRenderWindow, x: c_uint, y: c_uint); +pub fn sfTexture_updateFromPixels(texture: *mut sfTexture, pixels: *const u8, size: sfVector2u, dest: sfVector2u); +pub fn sfTexture_updateFromTexture(destination: *mut sfTexture, texture: *const sfTexture, dest: sfVector2u); +pub fn sfTexture_updateFromImage(texture: *mut sfTexture, image: *const sfImage, dest: sfVector2u); +pub fn sfTexture_updateFromWindow(texture: *mut sfTexture, window: *const sfWindow, dest: sfVector2u); +pub fn sfTexture_updateFromRenderWindow(texture: *mut sfTexture, renderWindow: *const sfRenderWindow, dest: sfVector2u); pub fn sfTexture_setSmooth(texture: *mut sfTexture, smooth: bool); pub fn sfTexture_isSmooth(texture: *const sfTexture) -> bool; -pub fn sfTexture_setSrgb(texture: *mut sfTexture, sRgb: bool); pub fn sfTexture_isSrgb(texture: *const sfTexture) -> bool; pub fn sfTexture_setRepeated(texture: *mut sfTexture, repeated: bool); pub fn sfTexture_isRepeated(texture: *const sfTexture) -> bool; @@ -389,11 +401,11 @@ pub fn sfTexture_getMaximumSize() -> c_uint; pub fn sfTransform_transformPoint(transform: *const sfTransform, point: sfVector2f) -> sfVector2f; pub fn sfTransform_transformRect(transform: *const sfTransform, rectangle: sfFloatRect) -> sfFloatRect; pub fn sfTransform_combine(transform: *mut sfTransform, other: *const sfTransform); -pub fn sfTransform_translate(transform: *mut sfTransform, x: f32, y: f32); +pub fn sfTransform_translate(transform: *mut sfTransform, offset: sfVector2f); pub fn sfTransform_rotate(transform: *mut sfTransform, angle: f32); -pub fn sfTransform_rotateWithCenter(transform: *mut sfTransform, angle: f32, centerX: f32, centerY: f32); -pub fn sfTransform_scale(transform: *mut sfTransform, scaleX: f32, scaleY: f32); -pub fn sfTransform_scaleWithCenter(transform: *mut sfTransform, scaleX: f32, scaleY: f32, centerX: f32, centerY: f32); +pub fn sfTransform_rotateWithCenter(transform: *mut sfTransform, angle: f32, center: sfVector2f); +pub fn sfTransform_scale(transform: *mut sfTransform, scale: sfVector2f); +pub fn sfTransform_scaleWithCenter(transform: *mut sfTransform, scale: sfVector2f, center: sfVector2f); // VertexBuffer.cpp pub fn sfVertexBuffer_new() -> *mut sfVertexBuffer; pub fn sfVertexBuffer_cpy(vertexBuffer: *const sfVertexBuffer) -> *mut sfVertexBuffer; @@ -418,11 +430,12 @@ pub fn sfView_setCenter(view: *mut sfView, center: sfVector2f); pub fn sfView_setSize(view: *mut sfView, size: sfVector2f); pub fn sfView_setRotation(view: *mut sfView, angle: f32); pub fn sfView_setViewport(view: *mut sfView, viewport: sfFloatRect); -pub fn sfView_reset(view: *mut sfView, rectangle: sfFloatRect); +pub fn sfView_setScissor(view: *mut sfView, scissor: sfFloatRect); pub fn sfView_getCenter(view: *const sfView) -> sfVector2f; pub fn sfView_getSize(view: *const sfView) -> sfVector2f; pub fn sfView_getRotation(view: *const sfView) -> f32; pub fn sfView_getViewport(view: *const sfView) -> sfFloatRect; +pub fn sfView_getScissor(view: *const sfView) -> sfFloatRect; pub fn sfView_move(view: *mut sfView, offset: sfVector2f); pub fn sfView_rotate(view: *mut sfView, angle: f32); pub fn sfView_zoom(view: *mut sfView, factor: f32); diff --git a/src/ffi/system.rs b/src/ffi/system.rs index 9e2c7c56..cd1e3379 100644 --- a/src/ffi/system.rs +++ b/src/ffi/system.rs @@ -17,5 +17,6 @@ type sfInputStreamHelperSeekCb = Option i64>; type sfInputStreamHelperTellCb = Option i64>; type sfInputStreamHelperGetSizeCb = Option i64>; +pub type sfBuffer = crate::system::buffer::Buffer; include!("system_bindgen.rs"); diff --git a/src/ffi/system_bindgen.rs b/src/ffi/system_bindgen.rs index 02341ab4..d8ff3988 100644 --- a/src/ffi/system_bindgen.rs +++ b/src/ffi/system_bindgen.rs @@ -3,11 +3,19 @@ unsafe extern "C" { +// Buffer.cpp +pub fn sfBuffer_destroy(buffer: *mut sfBuffer); +pub fn sfBuffer_getData(buffer: *const sfBuffer) -> *const u8; +pub fn sfBuffer_getSize(buffer: *const sfBuffer) -> usize; // Clock.cpp pub fn sfClock_new() -> *mut sfClock; pub fn sfClock_delete(clock: *mut sfClock); pub fn sfClock_getElapsedTime(clock: *const sfClock) -> i64; +pub fn sfClock_isRunning(clock: *const sfClock) -> bool; +pub fn sfClock_start(clock: *mut sfClock); +pub fn sfClock_stop(clock: *mut sfClock); pub fn sfClock_restart(clock: *mut sfClock) -> i64; +pub fn sfClock_reset(clock: *mut sfClock) -> i64; // InputStreamHelper.cpp pub fn sfInputStreamHelper_new(read: sfInputStreamHelperReadCb, seek: sfInputStreamHelperSeekCb, tell: sfInputStreamHelperTellCb, getSize: sfInputStreamHelperGetSizeCb, userData: *mut c_void) -> *mut sfInputStreamHelper; pub fn sfInputStreamHelper_del(stream: *mut sfInputStreamHelper); diff --git a/src/ffi/window.rs b/src/ffi/window.rs index bae0c02d..79a3f521 100644 --- a/src/ffi/window.rs +++ b/src/ffi/window.rs @@ -10,6 +10,7 @@ pub(super) type sfWindow = crate::window::Window; pub(super) type sfCursor = crate::window::Cursor; pub(crate) type sfVideoModeVector = crate::cpp::CppVector; pub(super) type sfContext = crate::window::Context; +pub(crate) type sfState = crate::window::window_enums::State; /// Enumeration of the native system cursor types. /// @@ -45,26 +46,47 @@ pub(super) type sfContext = crate::window::Context; #[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] #[allow(missing_docs)] pub enum sfCursorType { + /// Arrow cursor (default) Arrow, + /// Busy arrow cursor ArrowWait, + /// Busy cursor Wait, + /// I-beam, cursor when hovering over a field allowing text entry Text, + /// Pointing hand cursor Hand, + /// Horizontal double arrow cursor SizeHorizontal, + /// Vertical double arrow cursor SizeVertical, + /// Double arrow cursor going from top-left to bottom-right SizeTopLeftBottomRight, + /// Double arrow cursor going from bottom-left to top-right SizeBottomLeftTopRight, + /// Left arrow cursor on Linux, same as `SizeHorizontal` on other platforms SizeLeft, + /// Right arrow cursor on Linux, same as `SizeHorizontal` on other platforms SizeRight, + /// Up arrow cursor on Linux, same as `SizeVertical` on other platforms SizeTop, + /// Down arrow cursor on Linux, same as `SizeVertical` on other platforms SizeBottom, + /// Top-left arrow cursor on Linux, same as `SizeTopLeftBottomRight` on other platforms SizeTopLeft, + /// Bottom-right arrow cursor on Linux, same as `SizeTopLeftBottomRight` on other platforms SizeBottomRight, + /// Bottom-left arrow cursor on Linux, same as `SizeBottomLeftTopRight` on other platforms SizeBottomLeft, + /// Top-right arrow cursor on Linux, same as `SizeBottomLeftTopRight` on other platforms SizeTopRight, + /// Combination of `SizeHorizontal` and `SizeVertical` SizeAll, + /// Crosshair cursor Cross, + /// Help cursor Help, + /// Action not allowed cursor NotAllowed, } @@ -132,8 +154,7 @@ pub struct sfContextSettings { #[repr(C)] #[derive(Clone, Copy, Debug, PartialEq, Eq)] pub(crate) struct SizeEvent { - pub(crate) width: c_uint, - pub(crate) height: c_uint, + pub(crate) size: sfVector2u, } #[repr(C)] @@ -156,24 +177,27 @@ pub(crate) struct TextEvent { #[repr(C)] #[derive(Clone, Copy, Debug, PartialEq, Eq)] pub(crate) struct MouseMoveEvent { - pub(crate) x: c_int, - pub(crate) y: c_int, + pub(crate) position: sfVector2i, +} + +#[repr(C)] +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub(crate) struct MouseMoveRawEvent { + pub(crate) delta: sfVector2i, } #[repr(C)] #[derive(Clone, Copy, Debug, PartialEq, Eq)] pub(crate) struct MouseButtonEvent { pub(crate) button: MouseButton, - pub(crate) x: c_int, - pub(crate) y: c_int, + pub(crate) position: sfVector2i, } #[repr(C)] #[derive(Clone, Copy, Debug, PartialEq, Eq)] pub(crate) struct MouseWheelEvent { pub(crate) delta: c_int, - pub(crate) x: c_int, - pub(crate) y: c_int, + pub(crate) position: sfVector2i, } #[repr(C)] @@ -181,8 +205,7 @@ pub(crate) struct MouseWheelEvent { pub(crate) struct MouseWheelScrollEvent { pub(crate) wheel: MouseWheel, pub(crate) delta: f32, - pub(crate) x: c_int, - pub(crate) y: c_int, + pub(crate) position: sfVector2i, } #[repr(C)] @@ -210,17 +233,14 @@ pub(crate) struct JoystickButtonEvent { #[derive(Clone, Copy, Debug, PartialEq, Eq)] pub(crate) struct TouchEvent { pub(crate) finger: c_uint, - pub(crate) x: c_int, - pub(crate) y: c_int, + pub(crate) position: sfVector2i, } #[repr(C)] #[derive(Clone, Copy, Debug, PartialEq)] pub(crate) struct SensorEvent { pub(crate) type_: crate::ffi::window::sfSensorType, - pub(crate) x: f32, - pub(crate) y: f32, - pub(crate) z: f32, + pub(crate) value: sfVector3f, } #[repr(C)] @@ -229,16 +249,16 @@ pub(crate) struct SensorEvent { pub(crate) enum EventType { Closed, Resized, - LostFocus, - GainedFocus, + FocusLost, + FocusGained, TextEntered, KeyPressed, KeyReleased, - MouseWheelMoved, MouseWheelScrolled, MouseButtonPressed, MouseButtonReleased, MouseMoved, + MouseMovedRaw, MouseEntered, MouseLeft, JoystickButtonPressed, @@ -268,6 +288,7 @@ pub(crate) union EventUnion { pub(crate) key: KeyEvent, pub(crate) text: TextEvent, pub(crate) mouse_move: MouseMoveEvent, + pub(crate) mouse_move_raw: MouseMoveRawEvent, pub(crate) mouse_button: MouseButtonEvent, pub(crate) mouse_wheel: MouseWheelEvent, pub(crate) mouse_wheel_scroll: MouseWheelScrollEvent, @@ -319,8 +340,8 @@ pub enum MouseButton { Left, Right, Middle, - XButton1, - XButton2, + Extra1, + Extra2, } type sfMouseButton = MouseButton; @@ -383,10 +404,10 @@ pub enum Key { Semicolon, Comma, Period, - Quote, + Apostrophe, Slash, Backslash, - Tilde, + Grave, Equal, Hyphen, Space, @@ -589,10 +610,10 @@ pub enum Scancode { LaunchApplication2, LaunchMail, LaunchMediaSelect, - ScancodeCount, } -type sfKeyboardKey = Key; +type sfScancode = Scancode; +type sfKeyCode = Key; // Window handle is HWND (HWND__*) on Windows #[cfg(target_os = "windows")] @@ -619,9 +640,6 @@ pub enum sfSensorType { UserAcceleration, ///< Measures the absolute 3D orientation (degrees) Orientation, - - ///< Keep last -- the total number of sensor types - Count, } type sfGlFunctionPointer = *const c_void; diff --git a/src/ffi/window_bindgen.rs b/src/ffi/window_bindgen.rs index ccb843b1..db5b4f40 100644 --- a/src/ffi/window_bindgen.rs +++ b/src/ffi/window_bindgen.rs @@ -9,16 +9,16 @@ pub fn sfClipboard_setUnicodeString(text: *const u32); // Context.cpp pub fn sfContext_new() -> *mut sfContext; pub fn sfContext_del(context: *mut sfContext); +pub fn sfContext_isExtensionAvailable(name: *const c_char) -> bool; pub fn sfContext_setActive(context: *mut sfContext, active: bool) -> bool; pub fn sfContext_getSettings(context: *const sfContext) -> *const sfContextSettings; pub fn sfContext_getActiveContextId() -> u64; pub fn sfContext_getActiveContext() -> *const sfContext; pub fn sfContext_getFunction(name: *const c_char) -> sfGlFunctionPointer; // Cursor.cpp -pub fn sfCursor_new() -> *mut sfCursor; +pub fn sfCursor_createFromPixels(pixels: *const u8, size: sfVector2u, hotspot: sfVector2u) -> *mut sfCursor; +pub fn sfCursor_createFromSystem(type_: sfCursorType) -> *mut sfCursor; pub fn sfCursor_del(cursor: *mut sfCursor); -pub fn sfCursor_loadFromPixels(cursor: *mut sfCursor, pixels: *const u8, size: sfVector2u, hotspot: sfVector2u) -> bool; -pub fn sfCursor_loadFromSystem(cursor: *mut sfCursor, type_: sfCursorType) -> bool; // Joystick.cpp pub fn sfJoystick_isConnected(joystick: c_uint) -> bool; pub fn sfJoystick_getButtonCount(joystick: c_uint) -> c_uint; @@ -32,7 +32,11 @@ pub fn sfJoystickIdentification_getProductId(ident: *const sfJoystickIdentificat pub fn sfJoystickIdentification_getName(ident: *const sfJoystickIdentification) -> *const sfString; pub fn sfJoystick_update(); // Keyboard.cpp -pub fn sfKeyboard_isKeyPressed(key: sfKeyboardKey) -> bool; +pub fn sfKeyboard_isKeyPressed(key: sfKeyCode) -> bool; +pub fn sfKeyboard_isScancodePressed(code: sfScancode) -> bool; +pub fn sfKeyboard_localize(code: sfScancode) -> sfKeyCode; +pub fn sfKeyboard_delocalize(code: sfKeyCode) -> sfScancode; +pub fn sfKeyboard_getDescription(code: sfScancode) -> *mut sfString; pub fn sfKeyboard_setVirtualKeyboardVisible(visible: bool); // Mouse.cpp pub fn sfMouse_isButtonPressed(button: sfMouseButton) -> bool; @@ -57,19 +61,21 @@ pub fn sfVideoModeVector_getData(vec: *const sfVideoModeVector) -> *const sfVide // Window.cpp pub fn sfWindow_new() -> *mut sfWindow; pub fn sfWindow_del(window: *mut sfWindow); -pub fn sfWindow_create_mtss(window: *mut sfWindow, mode: sfVideoMode, title: *const u32, style: u32, settings: *const sfContextSettings); +pub fn sfWindow_create_mtsss(window: *mut sfWindow, mode: sfVideoMode, title: *const u32, style: u32, state: sfState, settings: *const sfContextSettings); pub fn sfWindow_create_handle_settings(window: *mut sfWindow, handle: sfWindowHandle, settings: *const sfContextSettings); pub fn sfWindow_close(window: *mut sfWindow); pub fn sfWindow_isOpen(window: *const sfWindow) -> bool; pub fn sfWindow_getSettings(window: *const sfWindow) -> *const sfContextSettings; pub fn sfWindow_pollEvent(window: *mut sfWindow, event: *mut sfEvent) -> bool; -pub fn sfWindow_waitEvent(window: *mut sfWindow, event: *mut sfEvent) -> bool; +pub fn sfWindow_waitEvent(window: *mut sfWindow, event: *mut sfEvent, timeout: i64) -> bool; pub fn sfWindow_getPosition(window: *const sfWindow) -> sfVector2i; pub fn sfWindow_setPosition(window: *mut sfWindow, position: sfVector2i); pub fn sfWindow_getSize(window: *const sfWindow) -> sfVector2u; pub fn sfWindow_setSize(window: *mut sfWindow, size: sfVector2u); +pub fn sfWindow_setMinimumSize(window: *mut sfWindow, size: *const sfVector2u); +pub fn sfWindow_setMaximumSize(window: *mut sfWindow, size: *const sfVector2u); pub fn sfWindow_setUnicodeTitle(window: *mut sfWindow, title: *const u32); -pub fn sfWindow_setIcon(window: *mut sfWindow, width: c_uint, height: c_uint, pixels: *const u8); +pub fn sfWindow_setIcon(window: *mut sfWindow, size: sfVector2u, pixels: *const u8); pub fn sfWindow_setVisible(window: *mut sfWindow, visible: bool); pub fn sfWindow_setMouseCursorVisible(window: *mut sfWindow, visible: bool); pub fn sfWindow_setMouseCursorGrabbed(window: *mut sfWindow, grabbed: bool); @@ -82,6 +88,6 @@ pub fn sfWindow_hasFocus(window: *const sfWindow) -> bool; pub fn sfWindow_display(window: *mut sfWindow); pub fn sfWindow_setFramerateLimit(window: *mut sfWindow, limit: c_uint); pub fn sfWindow_setJoystickThreshold(window: *mut sfWindow, threshold: f32); -pub fn sfWindow_getSystemHandle(window: *const sfWindow) -> sfWindowHandle; +pub fn sfWindow_getNativeHandle(window: *const sfWindow) -> sfWindowHandle; } \ No newline at end of file diff --git a/src/graphics/circle_shape.rs b/src/graphics/circle_shape.rs index 87ab1041..3c5d2267 100644 --- a/src/graphics/circle_shape.rs +++ b/src/graphics/circle_shape.rs @@ -5,7 +5,7 @@ use { Color, Drawable, FloatRect, IntRect, RenderStates, RenderTarget, Shape, Texture, Transform, Transformable, }, - system::Vector2f, + system::{Angle, Vector2f}, }, std::{ marker::PhantomData, @@ -99,8 +99,8 @@ impl Transformable for CircleShape<'_> { fn set_position>(&mut self, position: P) { unsafe { ffi::sfCircleShape_setPosition(self.handle.as_ptr(), position.into()) } } - fn set_rotation(&mut self, angle: f32) { - unsafe { ffi::sfCircleShape_setRotation(self.handle.as_ptr(), angle) } + fn set_rotation(&mut self, angle: Angle) { + unsafe { ffi::sfCircleShape_setRotation(self.handle.as_ptr(), angle.as_degrees()) } } fn set_scale>(&mut self, scale: S) { unsafe { ffi::sfCircleShape_setScale(self.handle.as_ptr(), scale.into()) } @@ -111,8 +111,8 @@ impl Transformable for CircleShape<'_> { fn position(&self) -> Vector2f { unsafe { ffi::sfCircleShape_getPosition(self.handle.as_ptr()) } } - fn rotation(&self) -> f32 { - unsafe { ffi::sfCircleShape_getRotation(self.handle.as_ptr()) } + fn rotation(&self) -> Angle { + unsafe { Angle::degrees(ffi::sfCircleShape_getRotation(self.handle.as_ptr())) } } fn get_scale(&self) -> Vector2f { unsafe { ffi::sfCircleShape_getScale(self.handle.as_ptr()) } @@ -123,8 +123,8 @@ impl Transformable for CircleShape<'_> { fn move_>(&mut self, offset: O) { unsafe { ffi::sfCircleShape_move(self.handle.as_ptr(), offset.into()) } } - fn rotate(&mut self, angle: f32) { - unsafe { ffi::sfCircleShape_rotate(self.handle.as_ptr(), angle) } + fn rotate(&mut self, angle: Angle) { + unsafe { ffi::sfCircleShape_rotate(self.handle.as_ptr(), angle.as_degrees()) } } fn scale>(&mut self, factors: F) { unsafe { ffi::sfCircleShape_scale(self.handle.as_ptr(), factors.into()) } @@ -186,6 +186,9 @@ impl<'s> Shape<'s> for CircleShape<'s> { fn global_bounds(&self) -> FloatRect { unsafe { ffi::sfCircleShape_getGlobalBounds(self.handle.as_ptr()) } } + fn geometric_center(&self) -> Vector2f { + unsafe { ffi::sfCircleShape_getGeometricCenter(self.handle.as_ptr()) } + } } impl<'s> Clone for CircleShape<'s> { diff --git a/src/graphics/convex_shape.rs b/src/graphics/convex_shape.rs index ea39b677..69b51bd4 100644 --- a/src/graphics/convex_shape.rs +++ b/src/graphics/convex_shape.rs @@ -5,7 +5,7 @@ use { Color, Drawable, FloatRect, IntRect, RenderStates, RenderTarget, Shape, Texture, Transform, Transformable, }, - system::Vector2f, + system::{Angle, Vector2f}, }, std::{ marker::PhantomData, @@ -109,8 +109,8 @@ impl Transformable for ConvexShape<'_> { fn set_position>(&mut self, position: P) { unsafe { ffi::sfConvexShape_setPosition(self.handle.as_ptr(), position.into()) } } - fn set_rotation(&mut self, angle: f32) { - unsafe { ffi::sfConvexShape_setRotation(self.handle.as_ptr(), angle) } + fn set_rotation(&mut self, angle: Angle) { + unsafe { ffi::sfConvexShape_setRotation(self.handle.as_ptr(), angle.as_degrees()) } } fn set_scale>(&mut self, scale: S) { unsafe { ffi::sfConvexShape_setScale(self.handle.as_ptr(), scale.into()) } @@ -121,8 +121,8 @@ impl Transformable for ConvexShape<'_> { fn position(&self) -> Vector2f { unsafe { ffi::sfConvexShape_getPosition(self.handle.as_ptr()) } } - fn rotation(&self) -> f32 { - unsafe { ffi::sfConvexShape_getRotation(self.handle.as_ptr()) } + fn rotation(&self) -> Angle { + unsafe { Angle::degrees(ffi::sfConvexShape_getRotation(self.handle.as_ptr())) } } fn get_scale(&self) -> Vector2f { unsafe { ffi::sfConvexShape_getScale(self.handle.as_ptr()) } @@ -133,8 +133,8 @@ impl Transformable for ConvexShape<'_> { fn move_>(&mut self, offset: O) { unsafe { ffi::sfConvexShape_move(self.handle.as_ptr(), offset.into()) } } - fn rotate(&mut self, angle: f32) { - unsafe { ffi::sfConvexShape_rotate(self.handle.as_ptr(), angle) } + fn rotate(&mut self, angle: Angle) { + unsafe { ffi::sfConvexShape_rotate(self.handle.as_ptr(), angle.as_degrees()) } } fn scale>(&mut self, factors: F) { unsafe { ffi::sfConvexShape_scale(self.handle.as_ptr(), factors.into()) } @@ -203,6 +203,9 @@ impl<'s> Shape<'s> for ConvexShape<'s> { fn global_bounds(&self) -> FloatRect { unsafe { ffi::sfConvexShape_getGlobalBounds(self.handle.as_ptr()) } } + fn geometric_center(&self) -> Vector2f { + unsafe { ffi::sfConvexShape_getGeometricCenter(self.handle.as_ptr()) } + } } impl<'s> Clone for ConvexShape<'s> { diff --git a/src/graphics/custom_shape.rs b/src/graphics/custom_shape.rs index 37aaa97c..cf09d6b5 100644 --- a/src/graphics/custom_shape.rs +++ b/src/graphics/custom_shape.rs @@ -5,7 +5,7 @@ use { Color, Drawable, FloatRect, IntRect, RenderStates, RenderTarget, Shape, Texture, Transform, Transformable, }, - system::Vector2f, + system::{Angle, Vector2f}, }, std::{ marker::PhantomData, @@ -154,6 +154,9 @@ impl<'s> Shape<'s> for CustomShape<'s> { fn global_bounds(&self) -> FloatRect { unsafe { ffi::sfCustomShape_getGlobalBounds(self.handle.as_ptr()) } } + fn geometric_center(&self) -> Vector2f { + unsafe { ffi::sfCustomShape_getGeometricCenter(self.handle.as_ptr()) } + } } impl Drawable for CustomShape<'_> { @@ -170,8 +173,8 @@ impl Transformable for CustomShape<'_> { fn set_position>(&mut self, position: P) { unsafe { ffi::sfCustomShape_setPosition(self.handle.as_ptr(), position.into()) } } - fn set_rotation(&mut self, angle: f32) { - unsafe { ffi::sfCustomShape_setRotation(self.handle.as_ptr(), angle) } + fn set_rotation(&mut self, angle: Angle) { + unsafe { ffi::sfCustomShape_setRotation(self.handle.as_ptr(), angle.as_degrees()) } } fn set_scale>(&mut self, scale: S) { unsafe { ffi::sfCustomShape_setScale(self.handle.as_ptr(), scale.into()) } @@ -182,8 +185,8 @@ impl Transformable for CustomShape<'_> { fn position(&self) -> Vector2f { unsafe { ffi::sfCustomShape_getPosition(self.handle.as_ptr()) } } - fn rotation(&self) -> f32 { - unsafe { ffi::sfCustomShape_getRotation(self.handle.as_ptr()) } + fn rotation(&self) -> Angle { + unsafe { Angle::degrees(ffi::sfCustomShape_getRotation(self.handle.as_ptr())) } } fn get_scale(&self) -> Vector2f { unsafe { ffi::sfCustomShape_getScale(self.handle.as_ptr()) } @@ -194,8 +197,8 @@ impl Transformable for CustomShape<'_> { fn move_>(&mut self, offset: O) { unsafe { ffi::sfCustomShape_move(self.handle.as_ptr(), offset.into()) } } - fn rotate(&mut self, angle: f32) { - unsafe { ffi::sfCustomShape_rotate(self.handle.as_ptr(), angle) } + fn rotate(&mut self, angle: Angle) { + unsafe { ffi::sfCustomShape_rotate(self.handle.as_ptr(), angle.as_degrees()) } } fn scale>(&mut self, factors: F) { unsafe { ffi::sfCustomShape_scale(self.handle.as_ptr(), factors.into()) } diff --git a/src/graphics/font.rs b/src/graphics/font.rs index ba67ced8..f9bf3c62 100644 --- a/src/graphics/font.rs +++ b/src/graphics/font.rs @@ -68,7 +68,7 @@ impl Font { /// See [`Self::load_from_file`]. pub fn from_file(path: &str) -> SfResult> { let mut new = Self::new()?; - new.load_from_file(path)?; + new.open_from_file(path)?; Ok(new) } /// Creates a new `Font` from font file data in memory. @@ -81,7 +81,7 @@ impl Font { pub unsafe fn from_memory(data: &[u8]) -> SfResult> { let mut new = Self::new()?; unsafe { - new.load_from_memory(data)?; + new.open_from_memory(data)?; } Ok(new) } @@ -103,7 +103,7 @@ impl Font { pub unsafe fn from_stream(stream: &mut T) -> SfResult> { let mut new = Self::new()?; unsafe { - new.load_from_stream(stream)?; + new.open_from_stream(stream)?; } Ok(new) } @@ -130,9 +130,9 @@ impl Font { /// } /// }; /// ``` - pub fn load_from_file(&mut self, path: &str) -> SfResult<()> { + pub fn open_from_file(&mut self, path: &str) -> SfResult<()> { let c_str = CString::new(path)?; - unsafe { ffi::sfFont_loadFromFile(self, c_str.as_ptr()) }.into_sf_result() + unsafe { ffi::sfFont_openFromFile(self, c_str.as_ptr()) }.into_sf_result() } /// Load the font from a custom stream. @@ -146,9 +146,9 @@ impl Font { /// /// # See also /// [`Font::from_file`], [`Font::from_memory`] - pub unsafe fn load_from_stream(&mut self, stream: &mut T) -> SfResult<()> { + pub unsafe fn open_from_stream(&mut self, stream: &mut T) -> SfResult<()> { let mut input_stream = InputStream::new(stream); - unsafe { ffi::sfFont_loadFromStream(self, &mut *input_stream.stream) }.into_sf_result() + unsafe { ffi::sfFont_openFromStream(self, &mut *input_stream.stream) }.into_sf_result() } /// Load the font from a file in memory. @@ -165,8 +165,8 @@ impl Font { /// # See also /// /// [`Font::from_file`], [`Font::from_stream`] - pub unsafe fn load_from_memory(&mut self, data: &[u8]) -> SfResult<()> { - unsafe { ffi::sfFont_loadFromMemory(self, data.as_ptr(), data.len()) }.into_sf_result() + pub unsafe fn open_from_memory(&mut self, data: &[u8]) -> SfResult<()> { + unsafe { ffi::sfFont_openFromMemory(self, data.as_ptr(), data.len()) }.into_sf_result() } /// Load the font from a file in static memory. /// @@ -174,7 +174,7 @@ impl Font { /// /// See [`Self::load_from_memory`]. pub fn load_from_memory_static(&mut self, data: &'static [u8]) -> SfResult<()> { - unsafe { self.load_from_memory(data) } + unsafe { self.open_from_memory(data) } } } @@ -269,6 +269,20 @@ impl Font { )) } } + + /// \brief Determine if this font has a glyph representing the requested code point + /// + /// Most fonts only include a very limited selection of glyphs from + /// specific Unicode subsets, like Latin, Cyrillic, or Asian characters. + /// + /// While code points without representation will return a font specific + /// default character, it might be useful to verify whether specific + /// code points are included to determine whether a font is suited + /// to display text in a specific language. + #[must_use] + pub fn has_glyph(&self, codepoint: u32) -> bool { + unsafe { ffi::sfFont_hasGlyph(self, codepoint) } + } /// Returns the font information. /// /// # Usage Example diff --git a/src/graphics/image.rs b/src/graphics/image.rs index d8e28707..4e3d1634 100644 --- a/src/graphics/image.rs +++ b/src/graphics/image.rs @@ -2,9 +2,9 @@ use { crate::{ IntoSfResult, SfResult, cpp::FBox, - ffi::graphics as ffi, + ffi::graphics::{self as ffi, sfImage_saveToMemory}, graphics::{Color, IntRect}, - system::{InputStream, Vector2u}, + system::{InputStream, Vector2u, buffer::Buffer}, }, std::{ error::Error, @@ -27,12 +27,10 @@ impl Image { FBox::new(unsafe { ffi::sfImage_new() }).into_sf_result() } /// Create a new `Image` filled with a solid color. - /// - /// See [`Self::recreate_solid`]. - pub fn new_solid(width: u32, height: u32, color: Color) -> SfResult> { - let mut new = Self::new()?; - new.recreate_solid(width, height, color); - Ok(new) + pub fn new_solid(size: Vector2u, color: Color) -> SfResult> { + let mut img = Self::new()?; + img.resize_with_color(size, color); + Ok(img) } /// Create a new `Image` from the provided RGBA pixel data. /// @@ -41,12 +39,10 @@ impl Image { /// # Safety /// /// Also see [`Self::recreate_from_pixels`]. - pub unsafe fn from_pixels(width: u32, height: u32, data: &[u8]) -> SfResult> { - let mut new = Self::new()?; - unsafe { - new.recreate_from_pixels(width, height, data); - } - Ok(new) + pub unsafe fn from_pixels(size: Vector2u, data: &[u8]) -> SfResult> { + let mut img = Self::new()?; + img.resize_with_pixels(size, data); + Ok(img) } /// Create a new `Image` from an image file on the filesystem. /// @@ -72,22 +68,6 @@ impl Image { new.load_from_stream(stream)?; Ok(new) } - /// Recreate with the given size, filled with a solid color. - pub fn recreate_solid(&mut self, width: u32, height: u32, color: Color) { - unsafe { - ffi::sfImage_create_w_h_color(self, width, height, color); - } - } - /// Recreate from the provided RGBA pixel data. - /// - /// # Safety - /// - /// `data` is assumed to contain 32-bit RGBA pixels, and match the given size. - pub unsafe fn recreate_from_pixels(&mut self, width: u32, height: u32, data: &[u8]) { - unsafe { - ffi::sfImage_create_w_h_pixels(self, width, height, data.as_ptr()); - } - } /// Load from image file data on the filesystem. /// /// The supported image formats are bmp, png, tga, jpg, gif, @@ -135,8 +115,8 @@ impl Image { /// This function doesn't check the validity of the pixel /// coordinates, using out-of-range values will result in /// an undefined behaviour. - pub unsafe fn set_pixel_unchecked(&mut self, x: u32, y: u32, color: Color) { - unsafe { ffi::sfImage_setPixel(self, x, y, color) } + pub unsafe fn set_pixel_unchecked(&mut self, coords: Vector2u, color: Color) { + unsafe { ffi::sfImage_setPixel(self, coords, color) } } /// Change the color of a pixel in an image @@ -145,24 +125,24 @@ impl Image { /// * x - X coordinate of pixel to change /// * y - Y coordinate of pixel to change /// * color - New color of the pixel - pub fn set_pixel(&mut self, x: u32, y: u32, color: Color) -> Result<(), PixelAccessError> { + pub fn set_pixel(&mut self, coords: Vector2u, color: Color) -> Result<(), PixelAccessError> { let image_size = self.size(); - if x >= image_size.x { + if coords.x >= image_size.x { return Err(PixelAccessError::XTooLarge { - x, + x: coords.x, width: image_size.x - 1, }); } - if y >= image_size.y { + if coords.y >= image_size.y { return Err(PixelAccessError::YTooLarge { - y, + y: coords.y, height: image_size.y - 1, }); } // Since we check for index validity before setting the pixel, it is safe unless the // image has been unloaded, but I doubt you can even do that. - unsafe { ffi::sfImage_setPixel(self, x, y, color) } + unsafe { ffi::sfImage_setPixel(self, coords, color) } Ok(()) } /// Get the color of a pixel in an image @@ -179,8 +159,8 @@ impl Image { /// coordinates, using out-of-range values will result in /// an undefined behaviour. #[must_use] - pub unsafe fn pixel_at_unchecked(&self, x: u32, y: u32) -> Color { - unsafe { ffi::sfImage_getPixel(self, x, y) } + pub unsafe fn pixel_at_unchecked(&self, coords: Vector2u) -> Color { + unsafe { ffi::sfImage_getPixel(self, coords) } } /// Get the color of a pixel in an image @@ -191,15 +171,15 @@ impl Image { /// /// Return the Color of the pixel at coordinates (x, y) #[must_use] - pub fn pixel_at(&self, x: u32, y: u32) -> Option { + pub fn pixel_at(&self, coords: Vector2u) -> Option { let image_size = self.size(); - if image_size.x <= x || image_size.y <= y { + if image_size.x <= coords.x || image_size.y <= coords.y { return None; } // Since we check for index validity before getting the pixel, it is safe unless the // image has been unloaded, but I doubt you can even do that. - unsafe { Some(ffi::sfImage_getPixel(self, x, y)) } + unsafe { Some(ffi::sfImage_getPixel(self, coords)) } } /// Return the memory buffer of this image. @@ -262,17 +242,30 @@ impl Image { pub fn copy_image( &mut self, source: &Image, - dest_x: u32, - dest_y: u32, + dest: Vector2u, source_rect: IntRect, apply_alpha: bool, - ) { - unsafe { ffi::sfImage_copy(self, source, dest_x, dest_y, source_rect, apply_alpha) } + ) -> SfResult<()> { + unsafe { ffi::sfImage_copy(self, source, dest, source_rect, apply_alpha) }.into_sf_result() } } /// Etc. impl Image { + /// Resize the image and fill it with a unique color + pub fn resize_with_color(&mut self, size: Vector2u, color: Color) { + unsafe { + ffi::sfImage_resizeWithColor(self, size, color); + } + } + /// Resize the image from an array of pixels + /// + /// The pixel array is assumed to contain 32-bits RGBA pixels, + /// and have the given `size`. If not, this is an undefined behavior. + /// If `pixels` is `nullptr`, an empty image is created. + pub fn resize_with_pixels(&mut self, size: Vector2u, data: &[u8]) { + unsafe { ffi::sfImage_resizeWithPixels(self, size, data.as_ptr()) } + } /// Save an image to a file on disk /// /// The format of the image is automatically deduced from @@ -289,6 +282,20 @@ impl Image { unsafe { ffi::sfImage_saveToFile(self, c_str.as_ptr()) }.into_sf_result() } + /// Save the image to a buffer in memory + /// + /// The format of the image must be specified. + /// The supported image formats are bmp, png, tga and jpg. + /// This function fails if the image is empty, or if + /// the format was invalid. + /// + /// Returns an optional buffer None for failure + #[must_use = "The returned buffer contains the saved data. Ignoring this result will discard the exported memory."] + pub fn save_to_memory(&self, format: &str) -> SfResult> { + let c_str = CString::new(format)?; + FBox::new(unsafe { sfImage_saveToMemory(self, c_str.as_ptr()) }).into_sf_result() + } + /// Return the size of an image /// /// Return the size in pixels diff --git a/src/graphics/mod.rs b/src/graphics/mod.rs index 1a08f7c9..dba78b92 100644 --- a/src/graphics/mod.rs +++ b/src/graphics/mod.rs @@ -1,5 +1,7 @@ //! 2D graphics module: sprites, text, shapes.. +use crate::system::Vector2f; + #[doc(inline)] pub use self::blend_mode::BlendMode; pub use { @@ -100,7 +102,10 @@ pub fn vertex_array_bounds(vertices: &[Vertex]) -> FloatRect { bottom = pos.y } } - FloatRect::new(left, top, right - left, bottom - top) + FloatRect::new( + Vector2f::new(left, top), + Vector2f::new(right - left, bottom - top), + ) } else { FloatRect::default() } diff --git a/src/graphics/primitive_type.rs b/src/graphics/primitive_type.rs index b550b006..148fe26b 100644 --- a/src/graphics/primitive_type.rs +++ b/src/graphics/primitive_type.rs @@ -24,6 +24,4 @@ impl PrimitiveType { /// List of connected triangles, a point uses the common center /// and the previous point to form a triangle. pub const TRIANGLE_FAN: Self = Self(ffi::graphics::sfPrimitiveType::TriangleFan); - /// List of individual quads (deprecated, don't work with OpenGL ES) - pub const QUADS: Self = Self(ffi::graphics::sfPrimitiveType::Quads); } diff --git a/src/graphics/rc_font.rs b/src/graphics/rc_font.rs index 65cef3f5..fdb5df92 100644 --- a/src/graphics/rc_font.rs +++ b/src/graphics/rc_font.rs @@ -288,6 +288,17 @@ impl RcFont { self.font.borrow_mut().set_smooth(smooth) } + /// Get the source font of an [`RcFont`] + /// + /// It let's you temprorarily borrow the [`Font`] bieng held by [`RcFont`]. + /// This may be useful for many things like using a temporary text object. + /// + /// Returns [`Font`] + #[must_use] + pub fn raw_font(&self) -> &Font { + unsafe { &*self.font.as_ptr() } + } + /// INTERNAL FUNCTION ONLY /// Allows other rc variants to request a weak pointer to the texture pub(super) fn downgrade(&self) -> std::rc::Weak>> { diff --git a/src/graphics/rc_sprite.rs b/src/graphics/rc_sprite.rs index 2376f1f6..a5c6f24e 100644 --- a/src/graphics/rc_sprite.rs +++ b/src/graphics/rc_sprite.rs @@ -1,4 +1,5 @@ use { + super::Rect, crate::{ cpp::FBox, ffi::graphics as ffi, @@ -6,7 +7,7 @@ use { Color, Drawable, FloatRect, IntRect, RcTexture, RenderStates, RenderTarget, Texture, Transform, Transformable, }, - system::Vector2f, + system::{Angle, Vector2f}, }, std::{cell::RefCell, ptr::NonNull, rc::Weak}, }; @@ -34,20 +35,6 @@ pub struct RcSprite { } impl RcSprite { - /// Create a new sprite - /// - /// # Panics - /// - /// Panics if for some reason a `Sprite` can't be created. - #[must_use] - pub fn new() -> Self { - let sp = unsafe { ffi::sfSprite_new() }; - Self { - handle: NonNull::new(sp).expect("Failed to create Sprite"), - texture: Weak::new(), - } - } - fn texture_exists(&self) -> bool { self.texture.strong_count() != 0 } @@ -59,17 +46,28 @@ impl RcSprite { /// Create a new sprite with a texture #[must_use] pub fn with_texture(texture: &RcTexture) -> RcSprite { - let mut sprite = Self::new(); - sprite.set_texture(texture, true); - sprite + Self::with_texture_and_rect( + texture, + Rect { + position: Default::default(), + size: texture.size().as_other(), + }, + ) } /// Create a new sprite with a texture and a source rectangle + /// + /// # Panics + /// Panics during const evaluation. + /// This method will panic during const evaluation if the string cannot be + /// determined to be null or not. #[must_use] pub fn with_texture_and_rect(texture: &RcTexture, rect: IntRect) -> RcSprite { - let mut sprite = Self::with_texture(texture); - sprite.set_texture_rect(rect); - sprite + let sp = unsafe { ffi::sfSprite_new(texture.raw_texture(), rect) }; + RcSprite { + handle: NonNull::new(sp).expect("Failed to create Sprite"), + texture: texture.downgrade(), + } } /// Change the source texture of a sprite @@ -229,12 +227,6 @@ impl RcSprite { } } -impl Default for RcSprite { - fn default() -> Self { - Self::new() - } -} - impl Clone for RcSprite { /// Return a new Sprite or panic! if there is not enough memory fn clone(&self) -> Self { @@ -272,12 +264,12 @@ impl Transformable for RcSprite { /// Reference [`Transformable::set_rotation`] for additional information /// /// Function fails, and prints an error message if `RcSprite`'s texture is dead. - fn set_rotation(&mut self, angle: f32) { + fn set_rotation(&mut self, angle: Angle) { if !self.texture_exists() { eprintln!("{ERROR_MSG}"); return; } - unsafe { ffi::sfSprite_setRotation(self.handle.as_ptr(), angle) } + unsafe { ffi::sfSprite_setRotation(self.handle.as_ptr(), angle.as_degrees()) } } /// Reference [`Transformable::set_scale`] for additional information /// @@ -312,12 +304,12 @@ impl Transformable for RcSprite { /// Reference [`Transformable::rotation`] for additional information /// /// Function fails, returns default, and prints an error message if `RcSprite`'s texture is dead. - fn rotation(&self) -> f32 { + fn rotation(&self) -> Angle { if !self.texture_exists() { eprintln!("{RETURN_ERROR_MSG}"); return Default::default(); } - unsafe { ffi::sfSprite_getRotation(self.handle.as_ptr()) } + Angle::degrees(unsafe { ffi::sfSprite_getRotation(self.handle.as_ptr()) }) } /// Reference [`Transformable::get_scale`] for additional information /// @@ -352,12 +344,12 @@ impl Transformable for RcSprite { /// Reference [`Transformable::rotate`] for additional information /// /// Function fails, and prints an error message if `RcSprite`'s texture is dead. - fn rotate(&mut self, angle: f32) { + fn rotate(&mut self, angle: Angle) { if !self.texture_exists() { eprintln!("{ERROR_MSG}"); return; } - unsafe { ffi::sfSprite_rotate(self.handle.as_ptr(), angle) } + unsafe { ffi::sfSprite_rotate(self.handle.as_ptr(), angle.as_degrees()) } } /// Reference [`Transformable::scale`] for additional information /// diff --git a/src/graphics/rc_text.rs b/src/graphics/rc_text.rs index dff32d7b..7d96ce23 100644 --- a/src/graphics/rc_text.rs +++ b/src/graphics/rc_text.rs @@ -6,7 +6,7 @@ use { Color, Drawable, FloatRect, Font, RcFont, RenderStates, RenderTarget, TextStyle, Transform, Transformable, }, - system::{SfStr, SfStrConv, Vector2f}, + system::{Angle, SfStr, SfStrConv, Vector2f}, }, std::{cell::RefCell, ptr::NonNull, rc::Weak}, }; @@ -43,16 +43,23 @@ impl RcText { /// /// Default value for characterSize on SFML is 30. /// + /// # Panics + /// Panics during const evaluation. + /// This method will panic during const evaluation if the string cannot be + /// determined to be null or not. + /// /// # Arguments /// * string - The string of the `RcText` /// * font - The [`RcFont`] to display the `RcText` /// * characterSize - The size of the `RcText` pub fn new(string: S, font: &RcFont, character_size: u32) -> Self { - let mut text = Self::default(); - text.set_string(string); - text.set_font(font); - text.set_character_size(character_size); - text + let text = string.with_as_sfstr(|sfstr| unsafe { + ffi::sfText_new(font.raw_font(), sfstr.as_ptr(), character_size) + }); + RcText { + handle: NonNull::new(text).expect("Failed to create Text"), + font: font.downgrade(), + } } fn font_exists(&self) -> bool { @@ -310,16 +317,6 @@ impl RcText { } } -impl Default for RcText { - fn default() -> Self { - let text = unsafe { ffi::sfText_new() }; - Self { - handle: NonNull::new(text).expect("Failed to create Text"), - font: Weak::new(), - } - } -} - impl Clone for RcText { /// Return a new Text or panic! if there is not enough memory fn clone(&self) -> Self { @@ -359,12 +356,12 @@ impl Transformable for RcText { /// /// # Warning /// Function fails, and prints an error message if `RcText`'s font is dead. - fn set_rotation(&mut self, angle: f32) { + fn set_rotation(&mut self, angle: Angle) { if !self.font_exists() { eprintln!("{ERROR_MSG}"); return; } - unsafe { ffi::sfText_setRotation(self.handle.as_ptr(), angle) } + unsafe { ffi::sfText_setRotation(self.handle.as_ptr(), angle.as_degrees()) } } /// Reference [`Transformable::set_scale`] for additional information /// @@ -403,12 +400,12 @@ impl Transformable for RcText { /// /// # Warning /// Function fails, returns default, and prints an error message if [`RcFont`] is dead. - fn rotation(&self) -> f32 { + fn rotation(&self) -> Angle { if !self.font_exists() { eprintln!("{RETURN_ERROR_MSG}"); return Default::default(); } - unsafe { ffi::sfText_getRotation(self.handle.as_ptr()) } + Angle::degrees(unsafe { ffi::sfText_getRotation(self.handle.as_ptr()) }) } /// Reference [`Transformable::get_scale`] for additional information /// @@ -447,12 +444,12 @@ impl Transformable for RcText { /// /// # Warning /// Function fails, and prints an error message if `RcText`'s font is dead. - fn rotate(&mut self, angle: f32) { + fn rotate(&mut self, angle: Angle) { if !self.font_exists() { eprintln!("{ERROR_MSG}"); return; } - unsafe { ffi::sfText_rotate(self.handle.as_ptr(), angle) } + unsafe { ffi::sfText_rotate(self.handle.as_ptr(), angle.as_degrees()) } } /// Reference [`Transformable::scale`] for additional information /// diff --git a/src/graphics/rc_texture.rs b/src/graphics/rc_texture.rs index 744ef067..20508e16 100644 --- a/src/graphics/rc_texture.rs +++ b/src/graphics/rc_texture.rs @@ -113,16 +113,6 @@ impl RcTexture { }) } - /// Create the texture. - /// - /// If this function fails, the texture is left unchanged. - /// - /// Returns whether creation was successful. - #[must_use = "Check if texture was created successfully"] - pub fn create(&mut self, width: u32, height: u32) -> SfResult<()> { - self.texture.borrow_mut().create(width, height) - } - /// Get the source texture of an [`RcTexture`] /// /// It let's you temporarily borrow the [`Texture`] being held by an [`RcTexture`]. @@ -145,8 +135,8 @@ impl RcTexture { /// # Arguments /// * mem - Pointer to the file data in memory /// * area - Area of the image to load - pub fn load_from_memory(&mut self, mem: &[u8], area: IntRect) -> SfResult<()> { - self.texture.borrow_mut().load_from_memory(mem, area) + pub fn load_from_memory(&mut self, mem: &[u8], srgb: bool, area: IntRect) -> SfResult<()> { + self.texture.borrow_mut().load_from_memory(mem, srgb, area) } /// Load texture from a stream (a struct implementing Read + Seek) @@ -162,17 +152,22 @@ impl RcTexture { pub fn load_from_stream( &mut self, stream: &mut T, + srgb: bool, area: IntRect, ) -> SfResult<()> { - self.texture.borrow_mut().load_from_stream(stream, area) + self.texture + .borrow_mut() + .load_from_stream(stream, srgb, area) } /// Load texture from a file /// /// # Arguments /// * filename - Path of the image file to load - pub fn load_from_file(&mut self, filename: &str, area: IntRect) -> SfResult<()> { - self.texture.borrow_mut().load_from_file(filename, area) + pub fn load_from_file(&mut self, filename: &str, srgb: bool, area: IntRect) -> SfResult<()> { + self.texture + .borrow_mut() + .load_from_file(filename, srgb, area) } /// Convenience method to easily create and load a `RcTexture` from a file. @@ -194,8 +189,8 @@ impl RcTexture { /// /// # Arguments /// * image - Image to upload to the texture - pub fn load_from_image(&mut self, image: &Image, area: IntRect) -> SfResult<()> { - self.texture.borrow_mut().load_from_image(image, area) + pub fn load_from_image(&mut self, image: &Image, srgb: bool, area: IntRect) -> SfResult<()> { + self.texture.borrow_mut().load_from_image(image, srgb, area) } /// Update a part of the texture from the contents of a window. @@ -205,8 +200,8 @@ impl RcTexture { /// # Safety /// No additional check is performed on the size of the window, passing an invalid combination /// of window size and offset will lead to an _undefined behavior_. - pub unsafe fn update_from_window(&mut self, window: &Window, x: u32, y: u32) { - unsafe { self.texture.borrow_mut().update_from_window(window, x, y) } + pub unsafe fn update_from_window(&mut self, window: &Window, dest: Vector2u) { + unsafe { self.texture.borrow_mut().update_from_window(window, dest) } } /// Update a part of the texture from the contents of a render window. @@ -219,13 +214,12 @@ impl RcTexture { pub unsafe fn update_from_render_window( &mut self, render_window: &RenderWindow, - x: u32, - y: u32, + dest: Vector2u, ) { unsafe { self.texture .borrow_mut() - .update_from_render_window(render_window, x, y) + .update_from_render_window(render_window, dest) } } @@ -236,8 +230,8 @@ impl RcTexture { /// # Safety /// No additional check is performed on the size of the image, passing an invalid combination /// of image size and offset will lead to an _undefined behavior_. - pub unsafe fn update_from_image(&mut self, image: &Image, x: u32, y: u32) { - unsafe { self.texture.borrow_mut().update_from_image(image, x, y) } + pub unsafe fn update_from_image(&mut self, image: &Image, dest: Vector2u) { + unsafe { self.texture.borrow_mut().update_from_image(image, dest) } } /// Update a part of this texture from another texture. @@ -248,8 +242,8 @@ impl RcTexture { /// No additional check is performed on the size of the texture, /// passing an invalid combination of texture size and offset will /// lead to an _undefined behavior_. - pub unsafe fn update_from_texture(&mut self, texture: &Texture, x: u32, y: u32) { - unsafe { self.texture.borrow_mut().update_from_texture(texture, x, y) } + pub unsafe fn update_from_texture(&mut self, texture: &Texture, dest: Vector2u) { + unsafe { self.texture.borrow_mut().update_from_texture(texture, dest) } } /// Update a part of the texture from an array of pixels. @@ -262,10 +256,10 @@ impl RcTexture { /// # Panics /// /// Panics the provided parameters would result in out of bounds access. - pub fn update_from_pixels(&mut self, pixels: &[u8], width: u32, height: u32, x: u32, y: u32) { + pub fn update_from_pixels(&mut self, pixels: &[u8], size: Vector2u, dest: Vector2u) { self.texture .borrow_mut() - .update_from_pixels(pixels, width, height, x, y) + .update_from_pixels(pixels, size, dest) } /// Enable or disable the smooth filter on a texture @@ -306,24 +300,6 @@ impl RcTexture { Texture::maximum_size() } - /// Enable or disable conversion from sRGB. - /// - /// When providing texture data from an image file or memory, it can either be stored in a - /// linear color space or an sRGB color space. Most digital images account for gamma correction - /// already, so they would need to be "uncorrected" back to linear color space before being - /// processed by the hardware. The hardware can automatically convert it from the sRGB - /// color space to a linear color space when it gets sampled. When the rendered image gets - /// output to the final framebuffer, it gets converted back to sRGB. - /// - /// After enabling or disabling sRGB conversion, make sure to reload the texture data in - /// order for the setting to take effect. - /// - /// This option is only useful in conjunction with an sRGB capable framebuffer. - /// This can be requested during window creation. - pub fn set_srgb(&mut self, srgb: bool) { - self.texture.borrow_mut().set_srgb(srgb) - } - /// Generate a mipmap using the current texture data. /// /// Mipmaps are pre-computed chains of optimized textures. Each level of texture in a mipmap diff --git a/src/graphics/rect.rs b/src/graphics/rect.rs index 600fa0e9..3f694a1d 100644 --- a/src/graphics/rect.rs +++ b/src/graphics/rect.rs @@ -1,3 +1,6 @@ +use std::ops::Div; + +use num_traits::One; #[cfg(feature = "serde")] use serde::{Deserialize, Serialize}; use { @@ -11,14 +14,10 @@ use { #[derive(Clone, PartialEq, Eq, Debug, Copy, Default)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] pub struct Rect { - /// Left coordinate of the rectangle. - pub left: T, - /// Top coordinate of the rectangle. - pub top: T, - /// Width of the rectangle. - pub width: T, - /// Height of the rectangle. - pub height: T, + /// Position of the top left corner of the rectangle + pub position: Vector2, + /// Size of the rectangle + pub size: Vector2, } /// A [`Rect`] of `i32`. @@ -33,36 +32,11 @@ impl Rect { /// /// ``` /// # use sfml::graphics::Rect; - /// let rect = Rect::new(10, 10, 10, 10); - /// ``` - pub const fn new(left: T, top: T, width: T, height: T) -> Self { - Rect { - left, - top, - width, - height, - } - } - - /// Construct a rectangle from its position and size. - /// - /// # Usage Example - /// - /// ``` - /// # use sfml::graphics::Rect; /// # use sfml::system::Vector2; - /// let a = Vector2::new(10, 20); - /// let b = Vector2::new(30, 40); - /// let rect = Rect::from_vecs(a, b); - /// assert_eq!(rect, Rect::new(10, 20, 30, 40)); + /// let rect = Rect::new(Vector2::new(10, 10), Vector2::new(10, 10)); /// ``` - pub fn from_vecs(pos: Vector2, size: Vector2) -> Rect { - Rect { - left: pos.x, - top: pos.y, - width: size.x, - height: size.y, - } + pub const fn new(position: Vector2, size: Vector2) -> Self { + Rect { position, size } } /// Lossless conversion into `Rect`. @@ -71,22 +45,21 @@ impl Rect { /// /// ``` /// # use sfml::graphics::Rect; - /// let a = Rect::new(1u8, 2u8, 3u8, 4u8); + /// # use sfml::system::Vector2; + /// let a = Rect::new(Vector2::new(1u8, 2u8), Vector2::new(3u8, 4u8)); /// let b: Rect = a.into_other(); - /// assert_eq!(u8::try_from(b.top).unwrap(), a.top); - /// assert_eq!(u8::try_from(b.height).unwrap(), a.height); - /// assert_eq!(u8::try_from(b.left).unwrap(), a.left); - /// assert_eq!(u8::try_from(b.width).unwrap(), a.width); + /// assert_eq!(u8::try_from(b.position.y).unwrap(), a.position.y); + /// assert_eq!(u8::try_from(b.size.y).unwrap(), a.size.y); + /// assert_eq!(u8::try_from(b.position.x).unwrap(), a.position.x); + /// assert_eq!(u8::try_from(b.size.x).unwrap(), a.size.x); /// ``` pub fn into_other(self) -> Rect where T: Into, { Rect { - top: self.top.into(), - left: self.left.into(), - width: self.width.into(), - height: self.height.into(), + position: self.position.into_other(), + size: self.size.into_other(), } } /// Fallible conversion into `Rect` @@ -95,14 +68,15 @@ impl Rect { /// /// ``` /// # use sfml::graphics::Rect; - /// let a = Rect::new(1i16, 2i16, 3i16, 4i16); + /// # use sfml::system::Vector2; + /// let a = Rect::new(Vector2::new(1i16, 2i16), Vector2::new(3i16, 4i16)); /// let b: Rect = a.try_into_other().unwrap(); - /// assert_eq!(i16::from(b.top), a.top); - /// assert_eq!(i16::from(b.height), a.height); - /// assert_eq!(i16::from(b.left), a.left); - /// assert_eq!(i16::from(b.width), a.width); + /// assert_eq!(i16::from(b.position.y), a.position.y); + /// assert_eq!(i16::from(b.size.y), a.size.y); + /// assert_eq!(i16::from(b.position.x), a.position.x); + /// assert_eq!(i16::from(b.size.x), a.size.x); /// - /// let a = Rect::new(-1i16, -2i16, -3i16, -4i16); + /// let a = Rect::new(Vector2::new(-1i16, -2i16), Vector2::new(-3i16, -4i16)); /// let b = a.try_into_other::(); /// assert!(b.is_err()); /// ``` @@ -111,10 +85,8 @@ impl Rect { T: TryInto, { Ok(Rect { - left: self.left.try_into()?, - top: self.top.try_into()?, - width: self.width.try_into()?, - height: self.height.try_into()?, + position: self.position.try_into_other()?, + size: self.size.try_into_other()?, }) } /// Lossy conversion into `Rect` @@ -123,52 +95,23 @@ impl Rect { /// /// ``` /// # use sfml::graphics::Rect; - /// let a = Rect::new(2., 32.32, 3.34, 1.443); + /// # use sfml::system::Vector2; + /// let a = Rect::new(Vector2::new(2., 32.32), Vector2::new(3.34, 1.443)); /// let b: Rect = a.as_other(); - /// assert_eq!(b.top, 32); - /// assert_eq!(b.left, 2); - /// assert_eq!(b.width, 3); - /// assert_eq!(b.height, 1); + /// assert_eq!(b.position.y, 32); + /// assert_eq!(b.position.x, 2); + /// assert_eq!(b.size.x, 3); + /// assert_eq!(b.size.y, 1); /// ``` pub fn as_other(self) -> Rect where T: AsPrimitive, { Rect { - left: self.left.as_(), - top: self.top.as_(), - width: self.width.as_(), - height: self.height.as_(), + position: self.position.as_other(), + size: self.size.as_other(), } } - - /// Get the position of the rectangle's top-left corner - /// - /// # Usage Example - /// - /// ``` - /// # use sfml::graphics::Rect; - /// # use sfml::system::Vector2; - /// let a = Rect::new(1, 2, 3, 4); - /// assert_eq!(a.position(), Vector2::new(1, 2)); - /// ``` - pub fn position(self) -> Vector2 { - Vector2::new(self.left, self.top) - } - - /// Get the size of the rectangle - /// - /// # Usage Example - /// - /// ``` - /// # use sfml::graphics::Rect; - /// # use sfml::system::Vector2; - /// let a = Rect::new(1, 2, 3, 4); - /// assert_eq!(a.size(), Vector2::new(3, 4)); - /// ``` - pub fn size(self) -> Vector2 { - Vector2::new(self.width, self.height) - } } impl + Sub + Copy> Rect { @@ -180,40 +123,20 @@ impl + Sub + Copy> Rect { /// # use sfml::graphics::Rect; /// # use sfml::system::Vector2; /// // Passing case - /// let a = Rect::new(0, 0, 4, 4); + /// let a = Rect::new(Vector2::new(0, 0), Vector2::new(4, 4)); /// let b = Vector2::new(2, 2); /// assert!(a.contains(b)); /// /// // Failing case - /// let a = Rect::new(0, 0, 1, 1); + /// let a = Rect::new(Vector2::new(0, 0), Vector2::new(1, 1)); /// let b = Vector2::new(20, 10); /// assert!(!a.contains(b)); /// ``` #[inline] pub fn contains(self, point: Vector2) -> bool { - self.contains2(point.x, point.y) - } - - /// Check if a point is inside the rectangle's area. - /// - /// # Usage Example - /// - /// ``` - /// # use sfml::graphics::Rect; - /// // Passing case - /// let a = Rect::new(0, 0, 4, 4); - /// assert!(a.contains2(2, 2)); - /// - /// // Failing case - /// let a = Rect::new(0, 0, 1, 1); - /// assert!(!a.contains2(20, 10)); - /// ``` - pub fn contains2(self, x: T, y: T) -> bool { - // Based on SFML's implementation. - // Rectangles with negative dimensions are allowed. - let (min_x, max_x) = min_max(self.left, self.left + self.width); - let (min_y, max_y) = min_max(self.top, self.top + self.height); - x >= min_x && x < max_x && y >= min_y && y < max_y + let (min_x, max_x) = min_max(self.position.x, self.position.x + self.size.x); + let (min_y, max_y) = min_max(self.position.y, self.position.y + self.size.y); + point.x >= min_x && point.x < max_x && point.y >= min_y && point.y < max_y } /// Returns the intersection between two rectangles, if any. @@ -224,23 +147,24 @@ impl + Sub + Copy> Rect { /// # Usage Example /// ``` /// # use sfml::graphics::Rect; + /// # use sfml::system::Vector2; /// // Passing case - /// let a = Rect::new(0, 0, 2, 2); - /// let b = Rect::new(1, 1, 2, 2); - /// assert_eq!(a.intersection(&b), Some(Rect::new(1, 1, 1, 1))); + /// let a = Rect::new(Vector2::new(0, 0), Vector2::new(2, 2)); + /// let b = Rect::new(Vector2::new(1, 1), Vector2::new(2, 2)); + /// assert_eq!(a.intersection(&b), Some(Rect::new(Vector2::new(1, 1), Vector2::new(1, 1)))); /// /// // Failing case - /// let a = Rect::new(0, 0, 2, 2); - /// let b = Rect::new(2, 2, 2, 2); + /// let a = Rect::new(Vector2::new(0, 0), Vector2::new(2, 2)); + /// let b = Rect::new(Vector2::new(2, 2), Vector2::new(2, 2)); /// assert_eq!(a.intersection(&b), None); /// ``` pub fn intersection(self, other: &Rect) -> Option> { // Based on SFML's implementation. // Compute the min and max coordinates on various axes. - let (r1_min_x, r1_max_x) = min_max(self.left, self.left + self.width); - let (r1_min_y, r1_max_y) = min_max(self.top, self.top + self.height); - let (r2_min_x, r2_max_x) = min_max(other.left, other.left + other.width); - let (r2_min_y, r2_max_y) = min_max(other.top, other.top + other.height); + let (r1_min_x, r1_max_x) = min_max(self.position.x, self.position.x + self.size.x); + let (r1_min_y, r1_max_y) = min_max(self.position.y, self.position.y + self.size.y); + let (r2_min_x, r2_max_x) = min_max(other.position.x, other.position.x + other.size.x); + let (r2_min_y, r2_max_y) = min_max(other.position.y, other.position.y + other.size.y); // Compute the intersection. let left = max(r1_min_x, r2_min_x); let top = max(r1_min_y, r2_min_y); @@ -248,13 +172,35 @@ impl + Sub + Copy> Rect { let bottom = min(r1_max_y, r2_max_y); // Return the result. if left < right && top < bottom { - Some(Rect::new(left, top, right - left, bottom - top)) + Some(Rect::new( + Vector2::new(left, top), + Vector2::new(right - left, bottom - top), + )) } else { None } } } +impl Rect +where + T: Div + One + Add + Copy, +{ + /// Return the position of the center of the rectangle + /// + /// # Usage Example + /// ``` + /// # use sfml::graphics::Rect; + /// # use sfml::system::Vector2; + /// let a = Rect::new(Vector2::new(0, 0), Vector2::new(2, 2)).center(); + /// assert_eq!(a, Vector2::new(1, 1)); + /// ```` + pub fn center(self) -> Vector2 { + let two = T::one() + T::one(); + self.position + self.size / two + } +} + #[inline] fn min(a: T, b: T) -> T { if a < b { a } else { b } diff --git a/src/graphics/rectangle_shape.rs b/src/graphics/rectangle_shape.rs index c76262a9..743796b7 100644 --- a/src/graphics/rectangle_shape.rs +++ b/src/graphics/rectangle_shape.rs @@ -5,7 +5,7 @@ use { Color, Drawable, FloatRect, IntRect, RenderStates, RenderTarget, Shape, Texture, Transform, Transformable, }, - system::Vector2f, + system::{Angle, Vector2f}, }, std::{ marker::PhantomData, @@ -55,8 +55,8 @@ impl<'s> RectangleShape<'s> { #[must_use] pub fn from_rect(rect: FloatRect) -> Self { let mut shape = Self::new(); - shape.set_size((rect.width, rect.height)); - shape.set_position((rect.left, rect.top)); + shape.set_size(rect.size); + shape.set_position(rect.position); shape } @@ -100,8 +100,8 @@ impl Transformable for RectangleShape<'_> { fn set_position>(&mut self, position: P) { unsafe { ffi::sfRectangleShape_setPosition(self.handle.as_ptr(), position.into()) } } - fn set_rotation(&mut self, angle: f32) { - unsafe { ffi::sfRectangleShape_setRotation(self.handle.as_ptr(), angle) } + fn set_rotation(&mut self, angle: Angle) { + unsafe { ffi::sfRectangleShape_setRotation(self.handle.as_ptr(), angle.as_degrees()) } } fn set_scale>(&mut self, scale: S) { unsafe { ffi::sfRectangleShape_setScale(self.handle.as_ptr(), scale.into()) } @@ -112,8 +112,8 @@ impl Transformable for RectangleShape<'_> { fn position(&self) -> Vector2f { unsafe { ffi::sfRectangleShape_getPosition(self.handle.as_ptr()) } } - fn rotation(&self) -> f32 { - unsafe { ffi::sfRectangleShape_getRotation(self.handle.as_ptr()) } + fn rotation(&self) -> Angle { + Angle::degrees(unsafe { ffi::sfRectangleShape_getRotation(self.handle.as_ptr()) }) } fn get_scale(&self) -> Vector2f { unsafe { ffi::sfRectangleShape_getScale(self.handle.as_ptr()) } @@ -124,8 +124,8 @@ impl Transformable for RectangleShape<'_> { fn move_>(&mut self, offset: O) { unsafe { ffi::sfRectangleShape_move(self.handle.as_ptr(), offset.into()) } } - fn rotate(&mut self, angle: f32) { - unsafe { ffi::sfRectangleShape_rotate(self.handle.as_ptr(), angle) } + fn rotate(&mut self, angle: Angle) { + unsafe { ffi::sfRectangleShape_rotate(self.handle.as_ptr(), angle.as_degrees()) } } fn scale>(&mut self, factors: F) { unsafe { ffi::sfRectangleShape_scale(self.handle.as_ptr(), factors.into()) } @@ -184,6 +184,9 @@ impl<'s> Shape<'s> for RectangleShape<'s> { fn global_bounds(&self) -> FloatRect { unsafe { ffi::sfRectangleShape_getGlobalBounds(self.handle.as_ptr()) } } + fn geometric_center(&self) -> Vector2f { + unsafe { ffi::sfRectangleShape_getGeometricCenter(self.handle.as_ptr()) } + } } impl<'s> Clone for RectangleShape<'s> { diff --git a/src/graphics/render_states.rs b/src/graphics/render_states.rs index 288087d0..e5b4f610 100644 --- a/src/graphics/render_states.rs +++ b/src/graphics/render_states.rs @@ -1,4 +1,7 @@ -use crate::graphics::{BlendMode, Shader, Texture, Transform}; +use crate::{ + ffi::graphics::{CoordinateType, StencilMode}, + graphics::{BlendMode, Shader, Texture, Transform}, +}; /// Define the states used for drawing to a [`RenderTarget`]. /// @@ -53,8 +56,12 @@ use crate::graphics::{BlendMode, Shader, Texture, Transform}; pub struct RenderStates<'texture, 'shader, 'shader_texture: 'shader> { /// The blending mode pub blend_mode: BlendMode, + /// The Stencil mode + pub stencil_mode: StencilMode, /// The transform pub transform: Transform, + /// Texture coordinate type + pub coordinate_type: CoordinateType, /// The texture that will be bound pub texture: Option<&'texture Texture>, /// The shader that will be used @@ -67,7 +74,9 @@ impl RenderStates<'_, '_, '_> { /// This can be used in a const context, unlike the [`Default`] implementation. pub const DEFAULT: Self = Self { blend_mode: BlendMode::ALPHA, + stencil_mode: StencilMode::DEFAULT, transform: Transform::IDENTITY, + coordinate_type: CoordinateType::sfCoordinateTypePixels, texture: None, shader: None, }; diff --git a/src/graphics/render_target.rs b/src/graphics/render_target.rs index 2d6458e4..235a81cc 100644 --- a/src/graphics/render_target.rs +++ b/src/graphics/render_target.rs @@ -1,4 +1,5 @@ use crate::{ + ffi::graphics::StencilValue, graphics::{ CircleShape, Color, ConvexShape, CustomShape, Drawable, IntRect, PrimitiveType, RcSprite, RcText, RectangleShape, RenderStates, Sprite, Text, Vertex, VertexBuffer, View, @@ -30,6 +31,17 @@ pub trait RenderTarget { /// clear the screen fn clear(&mut self, color: Color); + /// Clear the stencil buffer to a specific value + /// + /// The specified value is truncated to the bit width of the current stencil buffer. + fn clear_stencil(&mut self, stencil_value: StencilValue); + + /// \brief Clear the entire target with a single color and stencil value + /// + /// The specified stencil value is truncated to the bit + /// width of the current stencil buffer. + fn clear_color_and_stencil(&mut self, stencil_value: StencilValue, color: Color); + /// return the current view fn view(&self) -> &View; @@ -42,6 +54,14 @@ pub trait RenderTarget { /// get the viewport of the render target fn viewport(&self, view: &View) -> IntRect; + /// \brief Get the scissor rectangle of a view, applied to this render target + /// + /// The scissor rectangle is defined in the view as a ratio. This + /// function simply applies this ratio to the current dimensions + /// of the render target to calculate the pixels rectangle + /// that the scissor rectangle actually covers in the target. + fn scissor(&self, view: &View) -> IntRect; + /// Convert a point from window coordinates to world coordinates /// /// This function finds the 2D position that matches the diff --git a/src/graphics/render_texture.rs b/src/graphics/render_texture.rs index 56f66484..b2f6dfb7 100644 --- a/src/graphics/render_texture.rs +++ b/src/graphics/render_texture.rs @@ -20,10 +20,9 @@ impl RenderTexture { /// Construct a new render texture /// /// # Arguments - /// * width - Width of the render texture - /// * height - Height of the render texture - pub fn new(width: u32, height: u32) -> SfResult> { - Self::with_settings(width, height, &ContextSettings::default()) + /// * size - size of new render texture + pub fn new(size: Vector2u) -> SfResult> { + Self::with_settings(size, &ContextSettings::default()) } /// Create a `RenderTexture` with the given `ContextSettings`. @@ -33,28 +32,30 @@ impl RenderTexture { /// Otherwise it is unnecessary, and you should call [`RenderTexture::new`]. /// /// # Parameters - /// * width - Width of the render-texture - /// * height - Height of the render-texture + /// * size - width and height of the render-texture /// * settings - Additional settings for the underlying OpenGL texture and context - pub fn with_settings( - width: u32, - height: u32, - settings: &ContextSettings, - ) -> SfResult> { + pub fn with_settings(size: Vector2u, settings: &ContextSettings) -> SfResult> { let mut new = FBox::new(unsafe { ffi::sfRenderTexture_new() }).into_sf_result()?; - new.recreate(width, height, settings)?; + new.resize(size, settings)?; Ok(new) } - /// Recreate this `RenderTexture` with the given width, height, and settings. - pub fn recreate( - &mut self, - width: u32, - height: u32, - settings: &ContextSettings, - ) -> SfResult<()> { - unsafe { ffi::sfRenderTexture_create(self, width, height, settings) }.into_sf_result() - } + /// Resize the render-texture + /// + /// The last parameter, `settings`, is useful if you want to enable + /// multi-sampling or use the render-texture for OpenGL rendering that + /// requires a depth or stencil buffer. Otherwise it is unnecessary, and + /// you should leave this parameter at its default value. + /// + /// After resizing, the contents of the render-texture are undefined. + /// Call `RenderTexture::clear` first to ensure a single color fill. + /// + /// # Parameters + /// * size - width and height of the render-texture + /// * settings - Additional settings for the underlying OpenGL texture and context + pub fn resize(&mut self, size: Vector2u, settings: &ContextSettings) -> SfResult<()> { + unsafe { ffi::sfRenderTexture_resize(self, size, settings) }.into_sf_result() + } /// Update the contents of the target texture pub fn display(&mut self) { unsafe { ffi::sfRenderTexture_display(self) } @@ -214,6 +215,17 @@ impl RenderTarget for RenderTexture { fn reset_gl_states(&mut self) { unsafe { ffi::sfRenderTexture_resetGLStates(self) } } + fn clear_stencil(&mut self, stencil_value: ffi::StencilValue) { + unsafe { ffi::sfRenderTexture_clearStencil(self, stencil_value) } + } + fn clear_color_and_stencil(&mut self, stencil_value: ffi::StencilValue, color: Color) { + unsafe { + ffi::sfRenderTexture_clearColorAndStencil(self, color, stencil_value); + } + } + fn scissor(&self, view: &View) -> IntRect { + unsafe { ffi::sfRenderTexture_getScissor(self, view) } + } } impl Drop for RenderTexture { diff --git a/src/graphics/render_window.rs b/src/graphics/render_window.rs index dd8f9e84..c213ffc6 100644 --- a/src/graphics/render_window.rs +++ b/src/graphics/render_window.rs @@ -7,8 +7,11 @@ use crate::{ RcText, RectangleShape, RenderStates, RenderTarget, Sprite, Text, Vertex, VertexBuffer, View, }, - system::{SfStrConv, Vector2f, Vector2i, Vector2u}, - window::{ContextSettings, Cursor, Event, Handle, Style, VideoMode, thread_safety}, + system::{SfStrConv, Time, Vector2f, Vector2i, Vector2u}, + window::{ + ContextSettings, Cursor, Event, Handle, Style, VideoMode, thread_safety, + window_enums::State, + }, }; decl_opaque! { @@ -46,37 +49,24 @@ impl RenderWindow { mode: V, title: S, style: Style, + state: State, settings: &ContextSettings, ) -> SfResult> { thread_safety::set_window_thread(); title.with_as_sfstr(|sfstr| { let ptr = unsafe { - ffi::sfRenderWindow_new_mtss(mode.into(), sfstr.as_ptr(), style.bits(), settings) + ffi::sfRenderWindow_new_mtsss( + mode.into(), + sfstr.as_ptr(), + style.bits(), + state, + settings, + ) }; FBox::new(ptr).ok_or(SfError::CallFailed) }) } - /// Recreate with new settings. See [`Self::new`] for more information. - pub fn recreate, S: SfStrConv>( - &mut self, - mode: V, - title: S, - style: Style, - settings: &ContextSettings, - ) { - thread_safety::set_window_thread(); - - title.with_as_sfstr(|sfstr| unsafe { - ffi::sfRenderWindow_create_mtss( - self, - mode.into(), - sfstr.as_ptr(), - style.bits(), - settings, - ); - }); - } /// Create a render window from an existing platform-specific window handle /// @@ -131,9 +121,11 @@ impl RenderWindow { /// sleep as long as no new event is received. /// /// Returns `Some(event)` or `None` if an error has occured - pub fn wait_event(&mut self) -> Option { + pub fn wait_event(&mut self, timeout: Time) -> Option { let mut event = std::mem::MaybeUninit::uninit(); - let have_event = unsafe { ffi::sfRenderWindow_waitEvent(self, event.as_mut_ptr()) }; + let have_event = unsafe { + ffi::sfRenderWindow_waitEvent(self, event.as_mut_ptr(), timeout.as_microseconds()) + }; if have_event { unsafe { Event::from_raw(&event.assume_init()) } } else { @@ -288,8 +280,7 @@ impl RenderWindow { /// pixels must be an array of width x height pixels in 32-bits RGBA format. /// /// # Arguments - /// * width - Icon's width, in pixels - /// * height - Icon's height, in pixels + /// * size - Size of window /// * pixels - Vector of pixels /// /// # Safety @@ -297,8 +288,8 @@ impl RenderWindow { /// `pixels` not being at least `width * height * 4` will likely cause undefined behavior. /// /// Platform-specific behavior is also unclear (limits on max size, etc). - pub unsafe fn set_icon(&mut self, width: u32, height: u32, pixels: &[u8]) { - unsafe { ffi::sfRenderWindow_setIcon(self, width, height, pixels.as_ptr()) } + pub unsafe fn set_icon(&mut self, size: Vector2u, pixels: &[u8]) { + unsafe { ffi::sfRenderWindow_setIcon(self, size, pixels.as_ptr()) } } /// Close a render window and destroy all the attached resources @@ -372,6 +363,26 @@ impl RenderWindow { unsafe { ffi::sfRenderWindow_setSize(self, size.into()) } } + /// Set the minimum rendering region size + /// + /// Pass `None` to unset the minimum size + pub fn set_minimum_size(&mut self, size: Option) { + let ptr = size.as_ref().map_or(std::ptr::null(), |v| v); + unsafe { + ffi::sfRenderWindow_setMinimumSize(self, ptr); + } + } + + /// Set the maximum rendering region size + /// + /// Pass `None` to unset the maximum size + pub fn set_maximum_size(&mut self, size: Option) { + let ptr = size.as_ref().map_or(std::ptr::null(), |v| v); + unsafe { + ffi::sfRenderWindow_setMaximumSize(self, ptr); + } + } + /// Set the displayed cursor to a native system cursor. /// /// Upon window creation, the arrow cursor is used by default. @@ -412,7 +423,7 @@ impl RenderWindow { /// doesn't support, or implement a temporary workaround until a bug is fixed. #[must_use] pub fn system_handle(&self) -> Handle { - unsafe { ffi::sfRenderWindow_getSystemHandle(self) } + unsafe { ffi::sfRenderWindow_getNativeHandle(self) } } } @@ -506,6 +517,15 @@ impl RenderTarget for RenderWindow { fn clear(&mut self, color: Color) { unsafe { ffi::sfRenderWindow_clear(self, color) } } + fn clear_stencil(&mut self, stencil_value: ffi::StencilValue) { + unsafe { ffi::sfRenderWindow_clearStencil(self, stencil_value) } + } + fn clear_color_and_stencil(&mut self, stencil_value: ffi::StencilValue, color: Color) { + unsafe { ffi::sfRenderWindow_clearColorAndStencil(self, color, stencil_value) } + } + fn scissor(&self, view: &View) -> IntRect { + unsafe { ffi::sfRenderWindow_getScissor(self, view) } + } } impl Drop for RenderWindow { diff --git a/src/graphics/shader.rs b/src/graphics/shader.rs index 31a44793..e33f1b6b 100644 --- a/src/graphics/shader.rs +++ b/src/graphics/shader.rs @@ -1,5 +1,5 @@ use { - super::ShaderType, + super::{Color, ShaderType}, crate::{ IntoSfResult, SfResult, cpp::FBox, @@ -468,6 +468,22 @@ impl<'texture> Shader<'texture> { Ok(()) } + /// Specify value for \p ivec4 uniform + /// + /// Identical to calling `set_uniform_ivec4` with an ivec4 already mapped from [`Color`] + /// Just a nice helper method that will convert [`Color`] into a [`IVec4`] for you + pub fn set_int_color_uniform(&mut self, name: &str, color: Color) -> SfResult<()> { + self.set_uniform_ivec4( + name, + glsl::IVec4 { + x: i32::from(color.r), + y: i32::from(color.g), + z: i32::from(color.b), + w: i32::from(color.a), + }, + ) + } + /// Specify value for `bool` uniform. pub fn set_uniform_bool(&mut self, name: &str, value: bool) -> SfResult<()> { let cstring = CString::new(name)?; diff --git a/src/graphics/shape.rs b/src/graphics/shape.rs index 571a20ee..d45a8287 100644 --- a/src/graphics/shape.rs +++ b/src/graphics/shape.rs @@ -51,6 +51,11 @@ pub trait Shape<'texture>: Drawable + Transformable { fn outline_thickness(&self) -> f32; /// Gets the total number of points of the shape. fn point_count(&self) -> usize; + /// Get the geometric center of the shape + /// + /// The returned poinst is in local coordinates, that is, the shape's transforms + /// (position, rotation, scale\) are not taken into account. + fn geometric_center(&self) -> Vector2f; /// Gets a point of the shape. /// /// The returned point is in local coordinates, that is, the shape's transforms diff --git a/src/graphics/sprite.rs b/src/graphics/sprite.rs index d3ba76fd..195c1286 100644 --- a/src/graphics/sprite.rs +++ b/src/graphics/sprite.rs @@ -1,11 +1,12 @@ use { + super::Rect, crate::{ ffi::graphics as ffi, graphics::{ Color, Drawable, FloatRect, IntRect, RenderStates, RenderTarget, Texture, Transform, Transformable, }, - system::Vector2f, + system::{Angle, Vector2f}, }, std::{marker::PhantomData, ptr::NonNull}, }; @@ -27,34 +28,31 @@ pub struct Sprite<'s> { } impl<'s> Sprite<'s> { - /// Create a new sprite - /// - /// # Panics - /// - /// Panics if a new `Sprite` can't be created for some reason. - #[must_use] - pub fn new() -> Sprite<'s> { - let sp = unsafe { ffi::sfSprite_new() }; - Sprite { - handle: NonNull::new(sp).expect("Failed to create Sprite"), - texture: PhantomData, - } - } - /// Create a new sprite with a texture #[must_use] pub fn with_texture(texture: &'s Texture) -> Sprite<'s> { - let mut sprite = Sprite::new(); - sprite.set_texture(texture, true); - sprite + Self::with_texture_and_rect( + texture, + Rect { + position: Default::default(), + size: texture.size().as_other(), + }, + ) } /// Create a new sprite with a texture and a source rectangle + /// + /// # Panics + /// Panics during const evaluation. + /// This method will panic during const evaluation if the pointer cannot be + /// determined to be null or not. #[must_use] pub fn with_texture_and_rect(texture: &'s Texture, rect: IntRect) -> Self { - let mut sprite = Sprite::with_texture(texture); - sprite.set_texture_rect(rect); - sprite + let sp = unsafe { ffi::sfSprite_new(texture, rect) }; + Sprite { + handle: NonNull::new(sp).expect("Failed to create Sprite"), + texture: PhantomData, + } } /// Change the source texture of a sprite @@ -163,12 +161,6 @@ impl<'s> Sprite<'s> { } } -impl Default for Sprite<'_> { - fn default() -> Self { - Self::new() - } -} - impl<'s> Clone for Sprite<'s> { /// Return a new Sprite or panic! if there is not enough memory fn clone(&self) -> Sprite<'s> { @@ -194,8 +186,8 @@ impl Transformable for Sprite<'_> { fn set_position>(&mut self, position: P) { unsafe { ffi::sfSprite_setPosition(self.handle.as_ptr(), position.into()) } } - fn set_rotation(&mut self, angle: f32) { - unsafe { ffi::sfSprite_setRotation(self.handle.as_ptr(), angle) } + fn set_rotation(&mut self, angle: Angle) { + unsafe { ffi::sfSprite_setRotation(self.handle.as_ptr(), angle.as_degrees()) } } fn set_scale>(&mut self, scale: S) { unsafe { ffi::sfSprite_setScale(self.handle.as_ptr(), scale.into()) } @@ -206,8 +198,8 @@ impl Transformable for Sprite<'_> { fn position(&self) -> Vector2f { unsafe { ffi::sfSprite_getPosition(self.handle.as_ptr()) } } - fn rotation(&self) -> f32 { - unsafe { ffi::sfSprite_getRotation(self.handle.as_ptr()) } + fn rotation(&self) -> Angle { + Angle::degrees(unsafe { ffi::sfSprite_getRotation(self.handle.as_ptr()) }) } fn get_scale(&self) -> Vector2f { unsafe { ffi::sfSprite_getScale(self.handle.as_ptr()) } @@ -218,8 +210,8 @@ impl Transformable for Sprite<'_> { fn move_>(&mut self, offset: O) { unsafe { ffi::sfSprite_move(self.handle.as_ptr(), offset.into()) } } - fn rotate(&mut self, angle: f32) { - unsafe { ffi::sfSprite_rotate(self.handle.as_ptr(), angle) } + fn rotate(&mut self, angle: Angle) { + unsafe { ffi::sfSprite_rotate(self.handle.as_ptr(), angle.as_degrees()) } } fn scale>(&mut self, factors: F) { unsafe { ffi::sfSprite_scale(self.handle.as_ptr(), factors.into()) } diff --git a/src/graphics/text.rs b/src/graphics/text.rs index f905f8af..2100a626 100644 --- a/src/graphics/text.rs +++ b/src/graphics/text.rs @@ -5,7 +5,7 @@ use { Color, Drawable, FloatRect, Font, RenderStates, RenderTarget, TextStyle, Transform, Transformable, }, - system::{SfStr, SfStrConv, Vector2f}, + system::{Angle, SfStr, SfStrConv, Vector2f}, }, std::{marker::PhantomData, ptr::NonNull}, }; @@ -30,18 +30,25 @@ pub struct Text<'s> { impl<'s> Text<'s> { /// Create a new text with initialized value /// - /// Default value for characterSize on SFML is 30. + /// Default value for characterSize on SFML is 30.i + /// + /// # Panics + /// Panics during const evaluation. + /// This method will panic during const evaluation if the string cannot be + /// determined to be null or not. /// /// # Arguments /// * string - The string of the text /// * font - The font to display the Text /// * characterSize - The size of the Text pub fn new(string: S, font: &'s Font, character_size: u32) -> Text<'s> { - let mut text = Text::default(); - text.set_string(string); - text.set_font(font); - text.set_character_size(character_size); - text + let text = string.with_as_sfstr(|sfstr| unsafe { + ffi::sfText_new(font, sfstr.as_ptr(), character_size) + }); + Text { + handle: NonNull::new(text).expect("Failed to create Text"), + font: PhantomData, + } } /// Set the string of a text @@ -247,16 +254,6 @@ impl<'s> Text<'s> { } } -impl Default for Text<'_> { - fn default() -> Self { - let text = unsafe { ffi::sfText_new() }; - Self { - handle: NonNull::new(text).expect("Failed to create Text"), - font: PhantomData, - } - } -} - impl<'s> Clone for Text<'s> { /// Return a new Text or panic! if there is not enough memory fn clone(&self) -> Text<'s> { @@ -282,8 +279,8 @@ impl Transformable for Text<'_> { fn set_position>(&mut self, position: P) { unsafe { ffi::sfText_setPosition(self.handle.as_ptr(), position.into()) } } - fn set_rotation(&mut self, angle: f32) { - unsafe { ffi::sfText_setRotation(self.handle.as_ptr(), angle) } + fn set_rotation(&mut self, angle: Angle) { + unsafe { ffi::sfText_setRotation(self.handle.as_ptr(), angle.as_degrees()) } } fn set_scale>(&mut self, scale: S) { unsafe { ffi::sfText_setScale(self.handle.as_ptr(), scale.into()) } @@ -294,8 +291,8 @@ impl Transformable for Text<'_> { fn position(&self) -> Vector2f { unsafe { ffi::sfText_getPosition(self.handle.as_ptr()) } } - fn rotation(&self) -> f32 { - unsafe { ffi::sfText_getRotation(self.handle.as_ptr()) } + fn rotation(&self) -> Angle { + Angle::degrees(unsafe { ffi::sfText_getRotation(self.handle.as_ptr()) }) } fn get_scale(&self) -> Vector2f { unsafe { ffi::sfText_getScale(self.handle.as_ptr()) } @@ -306,8 +303,8 @@ impl Transformable for Text<'_> { fn move_>(&mut self, offset: O) { unsafe { ffi::sfText_move(self.handle.as_ptr(), offset.into()) } } - fn rotate(&mut self, angle: f32) { - unsafe { ffi::sfText_rotate(self.handle.as_ptr(), angle) } + fn rotate(&mut self, angle: Angle) { + unsafe { ffi::sfText_rotate(self.handle.as_ptr(), angle.as_degrees()) } } fn scale>(&mut self, factors: F) { unsafe { ffi::sfText_scale(self.handle.as_ptr(), factors.into()) } diff --git a/src/graphics/texture.rs b/src/graphics/texture.rs index 1aa4b9e2..0f200312 100644 --- a/src/graphics/texture.rs +++ b/src/graphics/texture.rs @@ -1,8 +1,9 @@ use { + self::ffi::sfTexture_resize, crate::{ IntoSfResult, SfError, SfResult, cpp::FBox, - ffi::graphics::{self as ffi, sfTexture_create}, + ffi::graphics::{self as ffi}, graphics::{Image, IntRect, RenderWindow}, system::{InputStream, Vector2u}, window::Window, @@ -56,20 +57,24 @@ pub Texture; /// Creation and loading impl Texture { - /// Create the texture. - /// - /// If this function fails, the texture is left unchanged. - /// - /// Returns whether creation was successful. - #[must_use = "Check if texture was created successfully"] - pub fn create(&mut self, width: u32, height: u32) -> SfResult<()> { - unsafe { sfTexture_create(self, width, height) }.into_sf_result() - } /// Creates a new `Texture` pub fn new() -> SfResult> { FBox::new(unsafe { ffi::sfTexture_new() }).into_sf_result() } + /// Resize the texture + /// + /// If this function fails, the texture is left unchanged. + /// + /// # Arguments + /// size - Width and height of the texture + /// sRgb - `true` to enable sRGB conversion, `false` to disable it + /// + /// Returns `true` if resizing was successful, `false` if it failed + pub fn resize(&mut self, size: Vector2u, srgb: bool) -> bool { + unsafe { sfTexture_resize(self, size, srgb) } + } + /// Load texture from memory /// /// The `area` argument can be used to load only a sub-rectangle of the whole image. @@ -80,9 +85,9 @@ impl Texture { /// # Arguments /// * mem - Pointer to the file data in memory /// * area - Area of the image to load - pub fn load_from_memory(&mut self, mem: &[u8], area: IntRect) -> SfResult<()> { + pub fn load_from_memory(&mut self, mem: &[u8], srgb: bool, area: IntRect) -> SfResult<()> { unsafe { - ffi::sfTexture_loadFromMemory(self, mem.as_ptr().cast(), mem.len(), area) + ffi::sfTexture_loadFromMemory(self, mem.as_ptr().cast(), mem.len(), srgb, area) .into_sf_result() } } @@ -100,11 +105,13 @@ impl Texture { pub fn load_from_stream( &mut self, stream: &mut T, + srgb: bool, area: IntRect, ) -> SfResult<()> { let mut input_stream = InputStream::new(stream); unsafe { - ffi::sfTexture_loadFromStream(self, &mut *input_stream.stream, area).into_sf_result() + ffi::sfTexture_loadFromStream(self, &mut *input_stream.stream, srgb, area) + .into_sf_result() } } @@ -112,22 +119,22 @@ impl Texture { /// /// # Arguments /// * filename - Path of the image file to load - pub fn load_from_file(&mut self, filename: &str, area: IntRect) -> SfResult<()> { + pub fn load_from_file(&mut self, filename: &str, srgb: bool, area: IntRect) -> SfResult<()> { let c_str = CString::new(filename)?; - unsafe { ffi::sfTexture_loadFromFile(self, c_str.as_ptr(), area).into_sf_result() } + unsafe { ffi::sfTexture_loadFromFile(self, c_str.as_ptr(), srgb, area).into_sf_result() } } /// Convenience method to easily create and load a `Texture` from a file. pub fn from_file(filename: &str) -> SfResult> { let mut new = Self::new()?; - new.load_from_file(filename, IntRect::default())?; + new.load_from_file(filename, Default::default(), IntRect::default())?; Ok(new) } /// Convenience method to easily create and load a `Texture` from an iamge. - pub fn from_image(image: &Image, area: IntRect) -> SfResult> { + pub fn from_image(image: &Image, srgb: bool, area: IntRect) -> SfResult> { let mut new = Self::new()?; - new.load_from_image(image, area)?; + new.load_from_image(image, srgb, area)?; Ok(new) } @@ -140,8 +147,8 @@ impl Texture { /// If you want the entire image then use a default `IntRect`. /// If the area rectangle crosses the bounds of the image, /// it is adjusted to fit the image size. - pub fn load_from_image(&mut self, image: &Image, area: IntRect) -> SfResult<()> { - unsafe { ffi::sfTexture_loadFromImage(self, image, area).into_sf_result() } + pub fn load_from_image(&mut self, image: &Image, srgb: bool, area: IntRect) -> SfResult<()> { + unsafe { ffi::sfTexture_loadFromImage(self, image, srgb, area).into_sf_result() } } } @@ -213,23 +220,6 @@ impl Texture { pub fn set_repeated(&mut self, repeated: bool) { unsafe { ffi::sfTexture_setRepeated(self, repeated) } } - /// Enable or disable conversion from sRGB. - /// - /// When providing texture data from an image file or memory, it can either be stored in a - /// linear color space or an sRGB color space. Most digital images account for gamma correction - /// already, so they would need to be "uncorrected" back to linear color space before being - /// processed by the hardware. The hardware can automatically convert it from the sRGB - /// color space to a linear color space when it gets sampled. When the rendered image gets - /// output to the final framebuffer, it gets converted back to sRGB. - /// - /// After enabling or disabling sRGB conversion, make sure to reload the texture data in - /// order for the setting to take effect. - /// - /// This option is only useful in conjunction with an sRGB capable framebuffer. - /// This can be requested during window creation. - pub fn set_srgb(&mut self, srgb: bool) { - unsafe { ffi::sfTexture_setSrgb(self, srgb) } - } } /// OpenGL interop @@ -270,8 +260,8 @@ impl Texture { /// # Safety /// No additional check is performed on the size of the window, passing an invalid combination /// of window size and offset will lead to an _undefined behavior_. - pub unsafe fn update_from_window(&mut self, window: &Window, x: u32, y: u32) { - unsafe { ffi::sfTexture_updateFromWindow(self, window, x, y) } + pub unsafe fn update_from_window(&mut self, window: &Window, dest: Vector2u) { + unsafe { ffi::sfTexture_updateFromWindow(self, window, dest) } } /// Update a part of the texture from the contents of a render window. @@ -284,10 +274,9 @@ impl Texture { pub unsafe fn update_from_render_window( &mut self, render_window: &RenderWindow, - x: u32, - y: u32, + dest: Vector2u, ) { - unsafe { ffi::sfTexture_updateFromRenderWindow(self, render_window, x, y) } + unsafe { ffi::sfTexture_updateFromRenderWindow(self, render_window, dest) } } /// Update a part of the texture from an image. @@ -297,8 +286,8 @@ impl Texture { /// # Safety /// No additional check is performed on the size of the image, passing an invalid combination /// of image size and offset will lead to an _undefined behavior_. - pub unsafe fn update_from_image(&mut self, image: &Image, x: u32, y: u32) { - unsafe { ffi::sfTexture_updateFromImage(self, image, x, y) } + pub unsafe fn update_from_image(&mut self, image: &Image, dest: Vector2u) { + unsafe { ffi::sfTexture_updateFromImage(self, image, dest) } } /// Update a part of this texture from another texture. @@ -309,8 +298,8 @@ impl Texture { /// No additional check is performed on the size of the texture, /// passing an invalid combination of texture size and offset will /// lead to an _undefined behavior_. - pub unsafe fn update_from_texture(&mut self, texture: &Texture, x: u32, y: u32) { - unsafe { ffi::sfTexture_updateFromTexture(self, texture, x, y) } + pub unsafe fn update_from_texture(&mut self, texture: &Texture, dest: Vector2u) { + unsafe { ffi::sfTexture_updateFromTexture(self, texture, dest) } } /// Update a part of the texture from an array of pixels. @@ -322,14 +311,14 @@ impl Texture { /// # Panics /// /// Panics the provided parameters would result in out of bounds access. - pub fn update_from_pixels(&mut self, pixels: &[u8], width: u32, height: u32, x: u32, y: u32) { + pub fn update_from_pixels(&mut self, pixels: &[u8], size: Vector2u, dest: Vector2u) { let my_dims = self.size(); assert!( - x + width <= my_dims.x - && y + height <= my_dims.y - && pixels.len() >= (width * height * 4) as usize + dest.x + size.x <= my_dims.x + && dest.y + size.y <= my_dims.y + && pixels.len() >= (size.x * size.y * 4) as usize ); - unsafe { ffi::sfTexture_updateFromPixels(self, pixels.as_ptr(), width, height, x, y) } + unsafe { ffi::sfTexture_updateFromPixels(self, pixels.as_ptr(), size, dest) } } /// Swap the contents of this texture with those of another. diff --git a/src/graphics/transform.rs b/src/graphics/transform.rs index c077e452..c132d621 100644 --- a/src/graphics/transform.rs +++ b/src/graphics/transform.rs @@ -109,8 +109,8 @@ impl Transform { /// # Arguments /// * x - Offset to apply on X axis /// * y - Offset to apply on Y axis - pub fn translate(&mut self, x: f32, y: f32) { - unsafe { ffi::sfTransform_translate(self, x, y) } + pub fn translate(&mut self, translate: Vector2f) { + unsafe { ffi::sfTransform_translate(self, translate) } } /// Combine the current transform with a rotation @@ -132,8 +132,8 @@ impl Transform { /// * angle - Rotation angle, in degrees /// * `center_x` - X coordinate of the center of rotation /// * `center_y` - Y coordinate of the center of rotation - pub fn rotate_with_center(&mut self, angle: f32, center_x: f32, center_y: f32) { - unsafe { ffi::sfTransform_rotateWithCenter(self, angle, center_x, center_y) } + pub fn rotate_with_center(&mut self, angle: f32, center: Vector2f) { + unsafe { ffi::sfTransform_rotateWithCenter(self, angle, center) } } /// Combine the current transform with a scaling @@ -141,8 +141,8 @@ impl Transform { /// # Arguments /// * `scale_x` - Scaling factor on the X axis /// * `scale_y` - Scaling factor on the Y axis - pub fn scale(&mut self, scale_x: f32, scale_y: f32) { - unsafe { ffi::sfTransform_scale(self, scale_x, scale_y) } + pub fn scale(&mut self, scale: Vector2f) { + unsafe { ffi::sfTransform_scale(self, scale) } } /// Combine the current transform with a scaling @@ -157,8 +157,8 @@ impl Transform { /// * `scale_y` - Scaling factor on Y axis /// * `center_x` - X coordinate of the center of scaling /// * `center_y` - Y coordinate of the center of scaling - pub fn scale_with_center(&mut self, scale_x: f32, scale_y: f32, center_x: f32, center_y: f32) { - unsafe { ffi::sfTransform_scaleWithCenter(self, scale_x, scale_y, center_x, center_y) } + pub fn scale_with_center(&mut self, scale: Vector2f, center: Vector2f) { + unsafe { ffi::sfTransform_scaleWithCenter(self, scale, center) } } /// Apply a transform to a 2D point diff --git a/src/graphics/transformable.rs b/src/graphics/transformable.rs index 9aa3b77b..9d00253a 100644 --- a/src/graphics/transformable.rs +++ b/src/graphics/transformable.rs @@ -1,4 +1,7 @@ -use crate::{graphics::Transform, system::Vector2f}; +use crate::{ + graphics::Transform, + system::{Angle, Vector2f}, +}; /// Decomposed transform defined by a position, a rotation and a scale. pub trait Transformable { @@ -8,12 +11,12 @@ pub trait Transformable { /// See [`move_`](Self::move_) to apply an offset based on the previous position instead. /// The default position of a transformable object is (0, 0). fn set_position>(&mut self, position: P); - /// Set the orientation of the object in degrees. + /// Set the orientation of the object. /// /// This function completely overwrites the previous rotation. /// See the rotate function to add an angle based on the previous rotation instead. /// The default rotation of a transformable object is 0. - fn set_rotation(&mut self, angle: f32); + fn set_rotation(&mut self, angle: Angle); /// Sets the scale factors of the object. /// /// This function completely overwrites the previous scale. @@ -30,10 +33,10 @@ pub trait Transformable { fn set_origin>(&mut self, origin: O); /// Gets the position of the object. fn position(&self) -> Vector2f; - /// Gets the rotation of the object in degrees. + /// Gets the rotation of the object. /// /// The rotation is always in the range [0, 360]. - fn rotation(&self) -> f32; + fn rotation(&self) -> Angle; /// Gets the current scale of the object. fn get_scale(&self) -> Vector2f; /// Gets the local origin of the object. @@ -47,7 +50,7 @@ pub trait Transformable { /// /// This function adds to the current rotation of the object, unlike /// [`set_rotation`](Self::set_rotation), which overwrites it. - fn rotate(&mut self, angle: f32); + fn rotate(&mut self, angle: Angle); /// Scales the object. /// /// This function multiplies the current scale of the object, unlike diff --git a/src/graphics/vertex_buffer.rs b/src/graphics/vertex_buffer.rs index 5f9ba30f..5fd8ebec 100644 --- a/src/graphics/vertex_buffer.rs +++ b/src/graphics/vertex_buffer.rs @@ -184,7 +184,7 @@ impl VertexBuffer { /// use sfml::graphics::{PrimitiveType, VertexBuffer, VertexBufferUsage}; /// /// let mut vb1 = VertexBuffer::new(PrimitiveType::TRIANGLES, 32, VertexBufferUsage::STATIC).unwrap(); - /// let mut vb2 = VertexBuffer::new(PrimitiveType::QUADS, 12, VertexBufferUsage::DYNAMIC).unwrap(); + /// let mut vb2 = VertexBuffer::new(PrimitiveType::TRIANGLE_FAN, 12, VertexBufferUsage::DYNAMIC).unwrap(); /// /// // ... /// diff --git a/src/graphics/view.rs b/src/graphics/view.rs index fbcaacb9..c6b83fe0 100644 --- a/src/graphics/view.rs +++ b/src/graphics/view.rs @@ -4,7 +4,7 @@ use { cpp::{FBox, RawDefault}, ffi::graphics as ffi, graphics::FloatRect, - system::Vector2f, + system::{Angle, Vector2f}, }, std::ptr::NonNull, }; @@ -41,10 +41,13 @@ impl View { /// /// # Arguments /// * rectangle - The rectangle defining the zone to display - pub fn from_rect(rectangle: FloatRect) -> SfResult> { - let mut new = Self::new()?; - new.reset(rectangle); - Ok(new) + #[must_use] + pub fn from_rect(rectangle: FloatRect) -> FBox { + let mut view: FBox = Default::default(); + view.set_center(rectangle.center()); + view.set_size(rectangle.size); + + view } } @@ -80,6 +83,14 @@ impl View { pub fn viewport(&self) -> FloatRect { unsafe { ffi::sfView_getViewport(self) } } + + /// Get the scissor rectangle of the view + /// + /// Return the scissor rectangle, expressed as a factor of the target size + #[must_use] + pub fn scissor(&self) -> FloatRect { + unsafe { ffi::sfView_getScissor(self) } + } } /// Set properties @@ -89,17 +100,17 @@ impl View { /// The default rotation of a view is 0 degree. /// /// # Arguments - /// * angle - New angle, in degrees - pub fn set_rotation(&mut self, angle: f32) { - unsafe { ffi::sfView_setRotation(self, angle) } + /// * angle - New angle + pub fn set_rotation(&mut self, angle: Angle) { + unsafe { ffi::sfView_setRotation(self, angle.as_degrees()) } } /// Rotate a view relatively to its current orientation /// /// # Arguments - /// * angle - Angle to rotate, in degrees - pub fn rotate(&mut self, angle: f32) { - unsafe { ffi::sfView_rotate(self, angle) } + /// * angle - Angle to rotate + pub fn rotate(&mut self, angle: Angle) { + unsafe { ffi::sfView_rotate(self, angle.as_degrees()) } } /// Resize a view rectangle relatively to its current size @@ -157,14 +168,27 @@ impl View { unsafe { ffi::sfView_setViewport(self, viewport) } } - /// Reset a view to the given rectangle + /// Set the target scissor rectangle /// - /// Note that this function resets the rotation angle to 0. + /// The scissor rectangle, expressed as a factor (between 0 and 1) of + /// the `RenderTarget`, specifies the region of the `RenderTarget` whose + /// pixels are able to be modified by draw or clear operations. + /// Any pixels which lie outside of the scissor rectangle will + /// not be modified by draw or clear operations. + /// For example, a scissor rectangle which only allows modifications + /// to the right side of the target would be defined + /// with `sfView_setScissor(view, (sfFloatRect){{0.5f, 0.f}, {0.5f, 1.f}})`. + /// By default, a view has a scissor rectangle which allows + /// modifications to the entire target. This is equivalent to + /// disabling the scissor test entirely. Passing the default + /// scissor rectangle to this function will also disable + /// scissor testing. /// /// # Arguments - /// * rectangle - Rectangle defining the zone to display - pub fn reset(&mut self, rectangle: FloatRect) { - unsafe { ffi::sfView_reset(self, rectangle) } + /// * view - View object + /// * scissor - New scissor rectangle + pub fn set_scissor(&mut self, scissor: FloatRect) { + unsafe { ffi::sfView_setScissor(self, scissor) } } } diff --git a/src/system/angle.rs b/src/system/angle.rs new file mode 100644 index 00000000..00ac7623 --- /dev/null +++ b/src/system/angle.rs @@ -0,0 +1,596 @@ +//! Angle module providing flexible angle representation and manipulation. +//! +//! This module provides the `Angle` struct and related functionality for working +//! with angles in a type-safe and convenient way. Angles can be created from +//! degrees or radians and converted between units seamlessly. +//! +//! # Usage +//! +//! ```rust +//! # use sfml::system::Angle; +//! +//! // Create angles +//! let a1 = Angle::degrees(90.0); +//! let a2 = Angle::radians(std::f32::consts::PI / 2.0); +//! +//! // Convert between units +//! let deg_value = a1.as_degrees(); // 90.0 +//! let rad_value = a2.as_radians(); // ~1.5708 +//! +//! // Mathematical operations +//! let sum = a1 + a2; +//! let doubled = a1 * 2.0; +//! +//! // Angle wrapping +//! let wrapped = Angle::degrees(450.0).wrap_unsigned(); // 90 degrees +//! let signed = Angle::degrees(-270.0).wrap_signed(); // 90 degrees +//! ``` + +use std::cmp::{Ordering, PartialEq, PartialOrd}; +use std::f32::consts::{PI, TAU}; +use std::fmt::{Debug, Display, Formatter, Result as FmtResult}; +use std::ops::{ + Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Rem, RemAssign, Sub, SubAssign, +}; + +/// Internal utility functions +mod utils { + /// Computes positive remainder for angle wrapping + /// This ensures the result is always positive, unlike Rust's % operator + #[inline] + pub const fn positive_remainder(a: f32, b: f32) -> f32 { + let result = a % b; + if result >= 0.0 { result } else { result + b } + } +} + +/// Represents an angle value in a flexible way. +/// +/// `Angle` encapsulates an angle value that can be defined as either degrees +/// or radians, and allows reading the value in either unit. This provides +/// flexibility without imposing a fixed representation on the user. +/// +/// Internally, angles are stored as radians for precision and performance. +/// All mathematical operations preserve the angle semantics. +/// +/// # Examples +/// +/// ```rust +/// # use sfml::system::Angle; +/// +/// let a1 = Angle::degrees(90.0); +/// let radians_val = a1.as_radians(); // π/2 +/// +/// let a2 = Angle::radians(std::f32::consts::PI); +/// let degrees_val = a2.as_degrees(); // 180.0 +/// +/// // Mathematical operations +/// let sum = a1 + a2; // 270 degrees total +/// let scaled = a1 * 2.0; // 180 degrees +/// ``` +#[derive(Clone, Copy, Default)] +pub struct Angle { + /// Angle value stored internally as radians + radians: f32, +} + +impl Angle { + /// Creates an angle from a number of degrees. + /// + /// # Examples + /// + /// ```rust + /// # use sfml::system::Angle; + /// + /// let right_angle = Angle::degrees(90.0); + /// let straight_angle = Angle::degrees(180.0); + /// ``` + #[inline] + #[must_use] + pub const fn degrees(angle: f32) -> Angle { + Angle::new_radians(angle * (PI / 180.0)) + } + + /// Creates an angle from a number of radians. + /// + /// # Examples + /// + /// ```rust + /// # use sfml::system::Angle; + /// # use std::f32::consts::PI; + /// + /// let right_angle = Angle::radians(PI / 2.0); + /// let straight_angle = Angle::radians(PI); + /// ``` + #[inline] + #[must_use] + pub const fn radians(angle: f32) -> Angle { + Angle::new_radians(angle) + } + + /// Creates an angle from radians (internal constructor) + #[inline] + const fn new_radians(radians: f32) -> Self { + Self { radians } + } + + /// Returns the angle value as degrees. + /// + /// # Examples + /// + /// ```rust + /// # use sfml::system::Angle; + /// # use std::f32::consts::PI; + /// + /// let angle = Angle::radians(PI); + /// assert_eq!(angle.as_degrees(), 180.0); + /// ``` + #[inline] + #[must_use] + pub const fn as_degrees(self) -> f32 { + self.radians * (180.0 / PI) + } + + /// Returns the angle value as radians. + /// + /// # Examples + /// + /// ```rust + /// # use sfml::system::Angle; + /// use std::f32::consts::PI; + /// + /// let angle = Angle::degrees(180.0); + /// assert!((angle.as_radians() - PI).abs() < f32::EPSILON); + /// ``` + #[inline] + #[must_use] + pub const fn as_radians(self) -> f32 { + self.radians + } + + /// Wraps the angle to the range [-180°, 180°) (signed representation). + /// + /// This is similar to a modulo operation that constrains the angle to the + /// range [-π, π) in radians. The resulting angle represents an equivalent + /// rotation to the original angle. + /// + /// # Examples + /// + /// ```rust + /// # use sfml::system::Angle; + /// + /// let angle = Angle::degrees(450.0); + /// let wrapped = angle.wrap_signed(); + /// assert!((wrapped.as_degrees() - 90.).abs() < 0.0001); + /// + /// let angle = Angle::degrees(-270.0); + /// let wrapped = angle.wrap_signed(); + /// assert!((wrapped.as_degrees() - 90.).abs() < 0.0001); + /// ``` + #[inline] + #[must_use] + pub const fn wrap_signed(self) -> Self { + let wrapped = utils::positive_remainder(self.radians + PI, TAU) - PI; + Self::new_radians(wrapped) + } + + /// Wraps the angle to the range [0°, 360°) (unsigned representation). + /// + /// This is similar to a modulo operation that constrains the angle to the + /// range [0, 2π) in radians. The resulting angle represents an equivalent + /// rotation to the original angle. + /// + /// # Examples + /// + /// ```rust + /// # use sfml::system::Angle; + /// + /// let angle = Angle::degrees(450.0); + /// let wrapped = angle.wrap_unsigned(); + /// assert!((wrapped.as_degrees() - 90.).abs() < 0.0001); + /// + /// let angle = Angle::degrees(-90.0); + /// let wrapped = angle.wrap_unsigned(); + /// assert!((wrapped.as_degrees() - 270.).abs() < 0.0001); + /// ``` + #[inline] + #[must_use] + pub const fn wrap_unsigned(self) -> Self { + let wrapped = utils::positive_remainder(self.radians, TAU); + Self::new_radians(wrapped) + } +} + +// ============================================================================ +// Comparison operators +// ============================================================================ + +impl PartialEq for Angle { + #[inline] + fn eq(&self, other: &Self) -> bool { + self.radians == other.radians + } +} + +impl PartialOrd for Angle { + #[inline] + fn partial_cmp(&self, other: &Self) -> Option { + self.radians.partial_cmp(&other.radians) + } +} + +// ============================================================================ +// Arithmetic operators +// ============================================================================ + +impl Neg for Angle { + type Output = Angle; + + /// Negates an angle, representing rotation in the opposite direction. + /// + /// # Examples + /// + /// ```rust + /// # use sfml::system::Angle; + /// + /// let angle = Angle::degrees(90.0); + /// let negated = -angle; + /// assert_eq!(negated.as_degrees(), -90.0); + /// ``` + #[inline] + fn neg(self) -> Self::Output { + Angle::new_radians(-self.radians) + } +} + +impl Add for Angle { + type Output = Angle; + + /// Adds two angles together. + /// + /// # Examples + /// + /// ```rust + /// # use sfml::system::Angle; + /// + /// let a1 = Angle::degrees(45.0); + /// let a2 = Angle::degrees(45.0); + /// let sum = a1 + a2; + /// assert_eq!(sum.as_degrees(), 90.0); + /// ``` + #[inline] + fn add(self, other: Self) -> Self::Output { + Angle::new_radians(self.radians + other.radians) + } +} + +impl AddAssign for Angle { + /// Adds another angle to this angle in place. + #[inline] + fn add_assign(&mut self, other: Self) { + *self = *self + other; + } +} + +impl Sub for Angle { + type Output = Angle; + + /// Subtracts one angle from another. + /// + /// # Examples + /// + /// ```rust + /// # use sfml::system::Angle; + /// + /// let a1 = Angle::degrees(90.0); + /// let a2 = Angle::degrees(45.0); + /// let diff = a1 - a2; + /// assert_eq!(diff.as_degrees(), 45.0); + /// ``` + #[inline] + fn sub(self, other: Self) -> Self::Output { + Angle::new_radians(self.radians - other.radians) + } +} + +impl SubAssign for Angle { + /// Subtracts another angle from this angle in place. + #[inline] + fn sub_assign(&mut self, other: Self) { + *self = *self - other; + } +} + +impl Mul for Angle { + type Output = Angle; + + /// Multiplies an angle by a scalar value. + /// + /// # Examples + /// + /// ```rust + /// # use sfml::system::Angle; + /// + /// let angle = Angle::degrees(45.0); + /// let doubled = angle * 2.0; + /// assert_eq!(doubled.as_degrees(), 90.0); + /// ``` + #[inline] + fn mul(self, scalar: f32) -> Self::Output { + Angle::new_radians(self.radians * scalar) + } +} + +impl Mul for f32 { + type Output = Angle; + + /// Multiplies an angle by a scalar value (commutative). + #[inline] + fn mul(self, angle: Angle) -> Self::Output { + angle * self + } +} + +impl MulAssign for Angle { + /// Multiplies this angle by a scalar in place. + #[inline] + fn mul_assign(&mut self, scalar: f32) { + *self = *self * scalar; + } +} + +impl Div for Angle { + type Output = Angle; + + /// Divides an angle by a scalar value. + /// + /// # Panics + /// + /// Panics if the divisor is zero in debug mode. + /// + /// # Examples + /// + /// ```rust + /// # use sfml::system::Angle; + /// + /// let angle = Angle::degrees(90.0); + /// let half = angle / 2.0; + /// assert_eq!(half.as_degrees(), 45.0); + /// ``` + #[inline] + fn div(self, scalar: f32) -> Self::Output { + debug_assert!(scalar != 0.0, "Angle division by zero"); + Angle::new_radians(self.radians / scalar) + } +} + +impl DivAssign for Angle { + /// Divides this angle by a scalar in place. + #[inline] + fn div_assign(&mut self, scalar: f32) { + *self = *self / scalar; + } +} + +impl Div for Angle { + type Output = f32; + + /// Divides one angle by another, returning the ratio. + /// + /// # Panics + /// + /// Panics if the divisor angle is zero in debug mode. + /// + /// # Examples + /// + /// ```rust + /// # use sfml::system::Angle; + /// + /// let a1 = Angle::degrees(90.0); + /// let a2 = Angle::degrees(45.0); + /// let ratio = a1 / a2; + /// assert_eq!(ratio, 2.0); + /// ``` + #[inline] + fn div(self, other: Self) -> Self::Output { + debug_assert!(other.radians != 0.0, "Angle division by zero angle"); + self.radians / other.radians + } +} + +impl Rem for Angle { + type Output = Angle; + + /// Computes the remainder of angle division. + /// + /// This operation ensures the result is always positive, unlike Rust's + /// standard `%` operator. The right-hand angle must be greater than zero. + /// + /// # Panics + /// + /// Panics if the right-hand angle is zero in debug mode. + /// + /// # Examples + /// + /// ```rust + /// # use sfml::system::Angle; + /// + /// let a1 = Angle::degrees(270.0); + /// let a2 = Angle::degrees(360.0); + /// let rem = a1 % a2; + /// assert_eq!(rem.as_degrees(), 270.0); + /// + /// let a3 = Angle::degrees(-90.0); + /// let a4 = Angle::degrees(360.0); + /// let rem2 = a3 % a4; + /// assert_eq!(rem2.as_degrees(), 270.0); // Always positive + /// ``` + #[inline] + fn rem(self, other: Self) -> Self::Output { + debug_assert!(other.radians > 0.0, "Angle modulus by non-positive angle"); + Angle::new_radians(utils::positive_remainder(self.radians, other.radians)) + } +} + +impl RemAssign for Angle { + /// Computes the remainder in place. + #[inline] + fn rem_assign(&mut self, other: Self) { + *self = *self % other; + } +} + +// ============================================================================ +// Display implementations +// ============================================================================ + +impl Debug for Angle { + fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult { + f.debug_struct("Angle") + .field("degrees", &self.as_degrees()) + .field("radians", &self.radians) + .finish() + } +} + +impl Display for Angle { + /// Displays the angle in degrees with the degree symbol. + /// + /// # Examples + /// + /// ```rust + /// # use sfml::system::Angle; + /// + /// let angle = Angle::degrees(45.0); + /// assert_eq!(format!("{}", angle), "45°"); + /// ``` + fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult { + write!(f, "{}°", self.as_degrees()) + } +} + +#[cfg(test)] +mod tests { + use super::*; + use std::f32::consts::PI; + + fn assert_angle_eq(actual: Angle, expected_degrees: f32) { + let diff = (actual.as_degrees() - expected_degrees).abs(); + assert!( + diff < 0.0001, + "Expected {} degrees, got {} degrees (diff: {})", + expected_degrees, + actual.as_degrees(), + diff + ); + } + + #[test] + fn test_angle_creation() { + let deg_angle = Angle::degrees(90.0); + let rad_angle = Angle::radians(PI / 2.0); + + assert_angle_eq(deg_angle, 90.0); + assert_angle_eq(rad_angle, 90.0); + } + + #[test] + fn test_angle_conversion() { + let angle = Angle::degrees(180.0); + assert!((angle.as_radians() - PI).abs() < f32::EPSILON); + assert_eq!(angle.as_degrees(), 180.0); + } + + #[test] + fn test_angle_wrapping() { + // Test wrap_unsigned + assert_angle_eq(Angle::degrees(450.0).wrap_unsigned(), 90.0); + assert_angle_eq(Angle::degrees(-90.0).wrap_unsigned(), 270.0); + assert_angle_eq(Angle::degrees(720.0).wrap_unsigned(), 0.0); + + // Test wrap_signed + assert_angle_eq(Angle::degrees(450.0).wrap_signed(), 90.0); + assert_angle_eq(Angle::degrees(-270.0).wrap_signed(), 90.0); + assert_angle_eq(Angle::degrees(270.0).wrap_signed(), -90.0); + } + + #[test] + fn test_angle_arithmetic() { + let a1 = Angle::degrees(45.0); + let a2 = Angle::degrees(45.0); + + assert_angle_eq(a1 + a2, 90.0); + assert_angle_eq(a1 - a2, 0.0); + assert_angle_eq(a1 * 2.0, 90.0); + assert_angle_eq(a1 / 2.0, 22.5); + + let ratio = Angle::degrees(90.0) / Angle::degrees(45.0); + assert!((ratio - 2.0).abs() < f32::EPSILON); + } + + #[test] + fn test_angle_remainder() { + let a1 = Angle::degrees(270.0); + let a2 = Angle::degrees(360.0); + assert_angle_eq(a1 % a2, 270.0); + + // Test positive remainder behavior + let a3 = Angle::degrees(-90.0); + let a4 = Angle::degrees(360.0); + assert_angle_eq(a3 % a4, 270.0); + } + + #[test] + fn test_angle_comparison() { + let a1 = Angle::degrees(45.0); + let a2 = Angle::degrees(45.0); + let a3 = Angle::degrees(90.0); + + assert_eq!(a1, a2); + assert!(a1 < a3); + assert!(a3 > a1); + } + + #[test] + fn test_angle_negation() { + let angle = Angle::degrees(90.0); + let negated = -angle; + assert_angle_eq(negated, -90.0); + } + + #[test] + fn test_assignment_operators() { + let mut angle = Angle::degrees(45.0); + + angle += Angle::degrees(45.0); + assert_angle_eq(angle, 90.0); + + angle -= Angle::degrees(30.0); + assert_angle_eq(angle, 60.0); + + angle *= 2.0; + assert_angle_eq(angle, 120.0); + + angle /= 3.0; + assert_angle_eq(angle, 40.0); + + angle %= Angle::degrees(30.0); + assert_angle_eq(angle, 10.0); + } + + #[test] + fn test_zero_constant() { + assert_eq!(Angle::default().as_degrees(), 0.0); + assert_eq!(Angle::default().as_radians(), 0.0); + } + + #[test] + fn test_display_formatting() { + let angle = Angle::degrees(45.0); + assert_eq!(format!("{}", angle), "45°"); + + let debug_str = format!("{:?}", angle); + assert!(debug_str.contains("degrees")); + assert!(debug_str.contains("radians")); + } +} diff --git a/src/system/buffer.rs b/src/system/buffer.rs new file mode 100644 index 00000000..6c3947b2 --- /dev/null +++ b/src/system/buffer.rs @@ -0,0 +1,26 @@ +use std::ops::Deref; + +use crate::ffi::system::{sfBuffer_destroy, sfBuffer_getData, sfBuffer_getSize}; + +decl_opaque! { + pub Buffer; +} + +impl Deref for Buffer { + type Target = [u8]; + fn deref(&self) -> &[u8] { + let data = unsafe { sfBuffer_getData(self) }; + let size = unsafe { sfBuffer_getSize(self) }; + if data.is_null() || size == 0 { + &[] + } else { + unsafe { std::slice::from_raw_parts(data, size) } + } + } +} + +impl Drop for Buffer { + fn drop(&mut self) { + unsafe { sfBuffer_destroy(self) } + } +} diff --git a/src/system/clock.rs b/src/system/clock.rs index 20a8ace2..96fd4baf 100644 --- a/src/system/clock.rs +++ b/src/system/clock.rs @@ -11,7 +11,7 @@ decl_opaque! { /// # Usage example /// ``` /// # use sfml::system::Clock; - /// let mut clock = Clock::start().unwrap(); + /// let mut clock = Clock::new().unwrap(); /// // ... /// let time1 = clock.elapsed_time(); /// // ... @@ -33,7 +33,14 @@ impl Drop for Clock { impl Clock { /// Creates a new Clock and starts it automatically. - pub fn start() -> SfResult> { + /// + /// # Usage example + /// ``` + /// # use sfml::system::Clock; + /// let mut clock = Clock::new().unwrap(); + /// ``` + #[must_use = "You should use the result of `Clock::new()` to avoid losing the created clock."] + pub fn new() -> SfResult> { unsafe { FBox::new(ffi::sfClock_new()) }.into_sf_result() } @@ -43,16 +50,107 @@ impl Clock { /// (or the construction of the instance if [`restart`] has not been called). /// /// [`restart`]: Clock::restart + /// + /// # Usage example + /// ``` + /// # use sfml::system::Clock; + /// let mut clock = Clock::new().unwrap(); + /// clock.start(); + /// # use std::{thread, time::Duration}; + /// # thread::sleep(Duration::from_nanos(1)); + /// assert!(clock.elapsed_time() != Default::default()); + /// ``` #[must_use] pub fn elapsed_time(&self) -> Time { unsafe { Time::from_raw(ffi::sfClock_getElapsedTime(self)) } } + /// Check whether the clock is running + /// + /// returns true if the clock is running, false otherwise + /// + /// # Usage example + /// ``` + /// # use sfml::system::Clock; + /// let mut clock = Clock::new().unwrap(); + /// clock.start(); + /// assert!(clock.is_running()); + /// ``` + #[must_use] + pub fn is_running(&self) -> bool { + unsafe { ffi::sfClock_isRunning(self) } + } + + /// Start the clock + /// + /// see [`stop`]: `Clock::stop` + /// + /// # Usage example + /// ``` + /// # use sfml::system::Clock; + /// let mut clock = Clock::new().unwrap(); + /// clock.stop(); + /// assert_eq!(clock.is_running(), false); + /// clock.start(); + /// assert_eq!(clock.is_running(), true); + /// ``` + pub fn start(&mut self) { + unsafe { ffi::sfClock_start(self) } + } + + /// Stop the clock + /// + /// see [`start`]: `Clock::stop` + /// + /// # Usage example + /// ``` + /// # use sfml::system::Clock; + /// let mut clock = Clock::new().unwrap(); + /// clock.start(); + /// clock.stop(); + /// assert_eq!(clock.is_running(), false); + /// clock.start(); + /// assert_eq!(clock.is_running(), true); + /// ``` + pub fn stop(&mut self) { + unsafe { ffi::sfClock_stop(self) } + } + /// Restarts the clock. /// /// This function puts the time counter back to zero. /// It also returns the time elapsed since the clock was started. + /// + /// # Usage example + /// ``` + /// # use sfml::system::Clock; + /// let mut clock = Clock::new().unwrap(); + /// clock.start(); + /// # use std::{thread, time::Duration}; + /// # thread::sleep(Duration::from_nanos(1)); + /// assert!(clock.restart() != Default::default()); + /// assert_eq!(clock.is_running(), true); + /// ``` pub fn restart(&mut self) -> Time { unsafe { Time::from_raw(ffi::sfClock_restart(self)) } } + + /// Resets the clock. + /// + /// This function puts the time counter back to zero. + /// It also returns the time elapsed since the clock was started. + /// + /// # Usage example + /// ``` + /// # use sfml::system::Clock; + /// let mut clock = Clock::new().unwrap(); + /// clock.start(); + /// # use std::{thread, time::Duration}; + /// # thread::sleep(Duration::from_nanos(1)); + /// assert!(clock.reset() != Default::default()); + /// assert_eq!(clock.is_running(), false); + /// ``` + pub fn reset(&mut self) -> Time { + unsafe { Time::from_raw(ffi::sfClock_reset(self)) } + } } diff --git a/src/system/mod.rs b/src/system/mod.rs index cbf7c411..671d4e15 100644 --- a/src/system/mod.rs +++ b/src/system/mod.rs @@ -4,6 +4,7 @@ //! pub use self::{ + angle::Angle, clock::Clock, input_stream::InputStream, sleep::sleep, @@ -13,6 +14,8 @@ pub use self::{ vector3::{Vector3, Vector3f, Vector3i}, }; +mod angle; +pub(crate) mod buffer; mod clock; mod input_stream; mod sleep; diff --git a/src/system/vector2.rs b/src/system/vector2.rs index 02913563..2c3f65c1 100644 --- a/src/system/vector2.rs +++ b/src/system/vector2.rs @@ -1,5 +1,8 @@ +use crate::system::Angle; +use num_traits::Float; #[cfg(feature = "serde")] use serde::{Deserialize, Serialize}; + use { num_traits::{AsPrimitive, CheckedDiv}, std::ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Sub, SubAssign}, @@ -22,8 +25,7 @@ use { /// - `Vector2` is [`Vector2u`] /// /// The `Vector2` type has a small and simple interface, its x and y members can be -/// accessed directly (there are no accessors like `set_x()`, `get_x()`) and it contains no -/// mathematical function like dot product, cross product, length, etc. +/// accessed directly (there are no accessors like `set_x()`, `get_x()`). /// /// # Usage example /// @@ -70,6 +72,7 @@ impl Vector2 { pub const fn new(x: T, y: T) -> Self { Self { x, y } } + /// Lossless conversion into `Vector2`. /// /// # Usage example @@ -90,6 +93,7 @@ impl Vector2 { y: self.y.into(), } } + /// Fallible conversion into `Vector2` /// /// # Usage example @@ -116,6 +120,7 @@ impl Vector2 { y: self.y.try_into()?, }) } + /// Lossy conversion into `Vector2` /// /// # Usage example @@ -136,9 +141,7 @@ impl Vector2 { y: self.y.as_(), } } -} -impl + Add + Copy> Vector2 { /// Dot product of two 2D vectors. /// /// # Usage example @@ -149,9 +152,46 @@ impl + Add + Copy> Vector2 { /// let b = Vector2i::new(2, 4); /// assert_eq!(a.dot(b), 288); /// ``` - pub fn dot(self, rhs: Self) -> T { + pub fn dot(self, rhs: Self) -> T + where + T: Mul + Add + Copy, + { self.x * rhs.x + self.y * rhs.y } + + /// Length of the vector + /// + /// # Usage example + /// + /// ``` + /// # use sfml::system::Vector2f; + /// let a = Vector2f::new(3., 4.); + /// assert!((a.length() - 5.).abs() <= f32::EPSILON); + /// ``` + pub fn length(self) -> T + where + T: Mul + Add + Copy + Float, + { + self.length_sq().sqrt() + } + + /// Vector with the same direciton but length 1 + /// + /// # Usage example + /// + /// ``` + /// # use sfml::system::Vector2f; + /// let a = Vector2f::new(2., 2.).normalized(); + /// assert!((a.length() - 1.).abs() <= f32::EPSILON); + /// assert!((a.x - 2f32.sqrt()/2.).abs() <= f32::EPSILON); + /// ``` + pub fn normalized(self) -> Vector2 + where + T: Mul + Add + Copy + Float + Div, + { + self / self.length() + } + /// Square of vector's length. /// /// # Usage example @@ -161,12 +201,13 @@ impl + Add + Copy> Vector2 { /// let a = Vector2i::new(10, 9); /// assert_eq!(a.length_sq(), 181); /// ``` - pub fn length_sq(self) -> T { + pub fn length_sq(self) -> T + where + T: Mul + Add + Copy, + { self.dot(self) } -} -impl + Sub + Copy> Vector2 { /// Z component of the cross product of two 2D vectors. /// /// # Usage example @@ -177,12 +218,13 @@ impl + Sub + Copy> Vector2 { /// let b = Vector2i::new(21, 101); /// assert_eq!(a.cross(b), -1851); /// ``` - pub fn cross(self, rhs: Self) -> T { + pub fn cross(self, rhs: Self) -> T + where + T: Mul + Sub + Copy, + { self.x * rhs.y - self.y * rhs.x } -} -impl> Vector2 { /// Component-wise multiplication of self and rhs. /// /// # Usage example @@ -193,15 +235,16 @@ impl> Vector2 { /// let b = Vector2i::new(2, 2); /// assert_eq!(a.cwise_mul(b), Vector2i::new(2, 2)); /// ``` - pub fn cwise_mul(self, rhs: Self) -> Vector2 { + pub fn cwise_mul(self, rhs: Self) -> Vector2 + where + T: Mul, + { Self { x: self.x * rhs.x, y: self.y * rhs.y, } } -} -impl> Vector2 { /// Component-wise division of self and rhs. Panics on divide by zero /// /// # Usage example @@ -212,15 +255,16 @@ impl> Vector2 { /// let b = Vector2i::new(3, 3); /// assert_eq!(a.cwise_div(b), Vector2i::new(23, 23)); /// ``` - pub fn cwise_div(self, rhs: Self) -> Vector2 { + pub fn cwise_div(self, rhs: Self) -> Vector2 + where + T: Div, + { Vector2 { x: self.x / rhs.x, y: self.y / rhs.y, } } -} -impl + CheckedDiv> Vector2 { /// Component-wise checked division of self and rhs. Returns None on divide by zero /// /// # Usage example @@ -236,14 +280,15 @@ impl + CheckedDiv> Vector2 { /// let b = Vector2i::new(0, 3); /// assert_eq!(a.cwise_checked_div(b), None); /// ``` - pub fn cwise_checked_div(self, rhs: Self) -> Option> { + pub fn cwise_checked_div(self, rhs: Self) -> Option> + where + T: Div + CheckedDiv, + { let x = self.x.checked_div(&rhs.x)?; let y = self.y.checked_div(&rhs.y)?; Some(Vector2 { x, y }) } -} -impl> Vector2 { /// Returns a perpendicular vector rotated +90 degrees /// /// # Usage example @@ -253,9 +298,154 @@ impl> Vector2 { /// let a = Vector2i::new(21, -21); /// assert_eq!(a.perpendicular(), Vector2i::new(21, 21)); /// ``` - pub fn perpendicular(self) -> Vector2 { + pub fn perpendicular(self) -> Vector2 + where + T: Neg, + { Vector2::new(-self.y, self.x) } + + /// `checked_div` for scalar division + /// + /// # Usage Example + /// + /// ``` + /// # use sfml::system::Vector2i; + /// // Passing case + /// let a = Vector2i::new(420, 69); + /// assert_eq!(a.checked_div(1000), Some(Vector2i::new(0, 0))); + /// + /// // Failing case + /// assert_eq!(a.checked_div(0), None); + /// ``` + pub fn checked_div(self, rhs: T) -> Option> + where + T: CheckedDiv, + { + let x = self.x.checked_div(&rhs)?; + let y = self.y.checked_div(&rhs)?; + Some(Vector2 { x, y }) + } + /// Creates a vector from polar coordinates (magnitude and angle) + /// + /// # Usage example + /// + /// ``` + /// # use sfml::system::{Vector2f, Angle}; + /// let v = Vector2f::from_polar(5.0, Angle::degrees(90.0)); // 5 units pointing up + /// assert!((v.x - 0.0).abs() < 1e-6); + /// assert!((v.y - 5.0).abs() < 1e-6); + /// ``` + pub fn from_polar(r: T, phi: crate::system::Angle) -> Self + where + T: From + Copy + Mul, + { + let (sin, cos) = phi.as_radians().sin_cos(); + Self { + x: r * T::from(cos), + y: r * T::from(sin), + } + } + + /// Returns the angle of this vector from the positive X-axis + /// + /// # Usage example + /// + /// ``` + /// # use sfml::system::{Vector2f, Angle}; + /// let v = Vector2f::new(1.0, 1.0); + /// let angle = v.angle(); + /// assert!((angle.as_degrees() - 45.0).abs() < 0.001); + /// ``` + pub fn angle(self) -> crate::system::Angle + where + T: Float + Copy + Into, + { + debug_assert!( + self.x != T::zero() || self.y != T::zero(), + "Cannot calculate angle of zero vector" + ); + Angle::radians(T::atan2(self.y, self.x).into()) + } + + /// Returns the signed angle from this vector to another vector + /// + /// # Usage example + /// + /// ``` + /// # use sfml::system::{Vector2f, Angle}; + /// let v1 = Vector2f::new(1.0, 0.0); // pointing right + /// let v2 = Vector2f::new(0.0, 1.0); // pointing up + /// let angle = v1.angle_to(v2); + /// assert!((angle.as_degrees() - 90.0).abs() < 0.001); + /// ``` + pub fn angle_to(self, rhs: Self) -> crate::system::Angle + where + T: Float + Copy + Into, + { + debug_assert!( + self.x != T::zero() || self.y != T::zero(), + "Cannot calculate angle from zero vector" + ); + debug_assert!( + rhs.x != T::zero() || rhs.y != T::zero(), + "Cannot calculate angle to zero vector" + ); + + let cross = self.cross(rhs); + let dot = self.dot(rhs); + Angle::radians(T::atan2(cross, dot).into()) + } + + /// Returns this vector rotated by the specified angle + /// + /// # Usage example + /// + /// ``` + /// # use sfml::system::{Vector2f, Angle}; + /// let v = Vector2f::new(1.0, 0.0); // pointing right + /// let rotated = v.rotated_by(Angle::degrees(90.0)); // rotate 90 degrees + /// assert!((rotated.x - 0.0).abs() < 0.001); + /// assert!((rotated.y - 1.0).abs() < 0.001); + /// ``` + pub fn rotated_by(self, phi: crate::system::Angle) -> Self + where + T: Float + Copy + From, + { + let (sin, cos) = phi.as_radians().sin_cos(); + let (sin, cos) = (sin.into(), cos.into()); + + Self { + x: self.x * cos - self.y * sin, + y: self.x * sin + self.y * cos, + } + } + + /// Returns the projection of this vector onto the given axis + /// + /// # Usage example + /// + /// ``` + /// # use sfml::system::Vector2f; + /// let v = Vector2f::new(3.0, 4.0); + /// let axis = Vector2f::new(1.0, 0.0); // X-axis + /// let projected = v.projected_onto(axis); + /// assert!((projected.x - 3.0).abs() < f32::EPSILON); + /// assert!((projected.y - 0.0).abs() < f32::EPSILON); + /// ``` + pub fn projected_onto(self, axis: Self) -> Self + where + T: Float + Copy, + { + debug_assert!( + axis.x != T::zero() || axis.y != T::zero(), + "Cannot project onto zero vector" + ); + + let axis_length_sq = axis.length_sq(); + let projection_length = self.dot(axis) / axis_length_sq; + axis * projection_length + } } impl From<(T, T)> for Vector2 { @@ -457,27 +647,6 @@ impl DivAssign for Vector2 { } } -impl Vector2 { - /// `checked_div` for scalar division - /// - /// # Usage Example - /// - /// ``` - /// # use sfml::system::Vector2i; - /// // Passing case - /// let a = Vector2i::new(420, 69); - /// assert_eq!(a.checked_div(1000), Some(Vector2i::new(0, 0))); - /// - /// // Failing case - /// assert_eq!(a.checked_div(0), None); - /// ``` - pub fn checked_div(self, rhs: T) -> Option> { - let x = self.x.checked_div(&rhs)?; - let y = self.y.checked_div(&rhs)?; - Some(Vector2 { x, y }) - } -} - impl> Neg for Vector2 { type Output = Self; /// Negates the vector @@ -489,6 +658,7 @@ impl> Neg for Vector2 { /// use std::ops::Neg; /// let a = Vector2i::new(21, 21); /// assert_eq!(a.neg(), Vector2i::new(-21, -21)); + /// ``` fn neg(self) -> Self { Vector2 { x: -self.x, diff --git a/src/system/vector3.rs b/src/system/vector3.rs index 5f0c8345..4ab2027c 100644 --- a/src/system/vector3.rs +++ b/src/system/vector3.rs @@ -1,3 +1,4 @@ +use num_traits::Float; #[cfg(feature = "serde")] use serde::{Deserialize, Serialize}; use { @@ -53,6 +54,12 @@ pub struct Vector3 { /// Z coordinate of the vector. pub z: T, } +/// [`Vector3`] with `f32` coordinates. +pub type Vector3f = Vector3; +/// [`Vector3`] with `u32` coordinates. +pub type Vector3u = Vector3; +/// [`Vector3`] with `i32` coordinates. +pub type Vector3i = Vector3; impl Vector3 { /// Create a new `Vector3` with the given values. @@ -134,14 +141,6 @@ impl Vector3 { z: self.z.as_(), } } -} - -/// [`Vector3`] with `f32` coordinates. -pub type Vector3f = Vector3; -/// [`Vector3`] with `i32` coordinates. -pub type Vector3i = Vector3; - -impl + Add + Copy> Vector3 { /// Dot product of two 3D vectors. /// /// # Usage example @@ -153,9 +152,13 @@ impl + Add + Copy> Vector3 { /// /// assert_eq!(a.dot(b), 6942); /// ``` - pub fn dot(self, rhs: Self) -> T { + pub fn dot(self, rhs: Self) -> T + where + T: Mul + Add + Copy, + { self.x * rhs.x + self.y * rhs.y + self.z * rhs.z } + /// Square of vector's length. /// /// # Usage Example @@ -165,12 +168,13 @@ impl + Add + Copy> Vector3 { /// let a = Vector3i::new(9, 10, 21); /// assert_eq!(a.length_sq(), 622); /// ``` - pub fn length_sq(self) -> T { + pub fn length_sq(self) -> T + where + T: Mul + Add + Copy, + { self.dot(self) } -} -impl + Sub + Copy> Vector3 { /// Cross product of two 3D vectors. /// /// # Usage Example @@ -181,16 +185,17 @@ impl + Sub + Copy> Vector3 { /// let b = Vector3i::new(69, 420, 101); /// assert_eq!(a.cross(b), Vector3i::new(-7810, 540, 3090)); /// ``` - pub fn cross(self, rhs: Self) -> Vector3 { + pub fn cross(self, rhs: Self) -> Vector3 + where + T: Mul + Sub + Copy, + { Vector3 { x: self.y * rhs.z - self.z * rhs.y, y: self.z * rhs.x - self.x * rhs.z, z: self.x * rhs.y - self.y * rhs.x, } } -} -impl> Vector3 { /// Component-wise multiplication of self and rhs. /// /// # Usage Example @@ -201,16 +206,17 @@ impl> Vector3 { /// let b = Vector3i::new(2, 2, 2); /// assert_eq!(a.cwise_mul(b), Vector3i::new(2, 2, 2)); /// ``` - pub fn cwise_mul(self, rhs: Self) -> Vector3 { + pub fn cwise_mul(self, rhs: Self) -> Vector3 + where + T: Mul, + { Self { x: self.x * rhs.x, y: self.y * rhs.y, z: self.z * rhs.z, } } -} -impl> Vector3 { /// Component-wise division of self and rhs. Panics on divide by zero /// /// # Usage Example @@ -221,16 +227,17 @@ impl> Vector3 { /// let b = Vector3i::new(3, 3, 3); /// assert_eq!(a.cwise_div(b), Vector3i::new(3, 3, 3)); /// ``` - pub fn cwise_div(self, rhs: Self) -> Vector3 { + pub fn cwise_div(self, rhs: Self) -> Vector3 + where + T: Div, + { Vector3 { x: self.x / rhs.x, y: self.y / rhs.y, z: self.z / rhs.z, } } -} -impl + CheckedDiv> Vector3 { /// Component-wise checked division of self and rhs. Returns None on divide by zero /// /// # Usage Example @@ -245,12 +252,122 @@ impl + CheckedDiv> Vector3 { /// let b = Vector3i::new(3, 0, 3); /// assert_eq!(a.cwise_checked_div(b), None); /// ``` - pub fn cwise_checked_div(self, rhs: Self) -> Option> { + pub fn cwise_checked_div(self, rhs: Self) -> Option> + where + T: Div + CheckedDiv, + { let x = self.x.checked_div(&rhs.x)?; let y = self.y.checked_div(&rhs.y)?; let z = self.z.checked_div(&rhs.z)?; Some(Vector3 { x, y, z }) } + + /// `checked_div` for scalar division + /// + /// # Usage Example + /// + /// ``` + /// # use sfml::system::Vector3i; + /// // Passing case + /// let a = Vector3i::new(10, 10, 10); + /// assert_eq!(a.checked_div(3), Some(Vector3i::new(3, 3, 3))); + /// + /// // Failing case + /// assert_eq!(a.checked_div(0), None); + /// ``` + pub fn checked_div(self, rhs: T) -> Option> + where + T: CheckedDiv, + { + let x = self.x.checked_div(&rhs)?; + let y = self.y.checked_div(&rhs)?; + let z = self.z.checked_div(&rhs)?; + Some(Vector3 { x, y, z }) + } + + /// Returns the length (magnitude) of the vector. + /// + /// If you are not interested in the actual length, but only in comparisons, + /// consider using `length_sq()`. + /// + /// # Usage Example + /// ``` + /// # use sfml::system::Vector3f; + /// let v = Vector3f::new(3.0, 4.0, 12.0); + /// assert!((v.length() - 13.0).abs() < 1e-6); + /// ``` + #[inline] + pub fn length(self) -> T + where + T: Float, + { + self.length_sq().sqrt() + } + + /// Returns a normalized (unit length) vector with the same direction. + /// + /// # Panics + /// Panics in debug mode if the vector is zero. + /// + /// # Usage Example + /// ``` + /// # use sfml::system::Vector3f; + /// let v = Vector3f::new(3.0, 0.0, 4.0); + /// let n = v.normalized(); + /// assert!((n.length() - 1.0).abs() < 1e-6); + /// ``` + #[inline] + pub fn normalized(self) -> Vector3 + where + T: Float, + { + let len = self.length(); + Self { + x: self.x / len, + y: self.y / len, + z: self.z / len, + } + } +} + +impl From<(T, T, T)> for Vector3 { + /// Constructs a `Vector3` from `(x, y, z)`. + /// + /// # Usage Example + /// + /// ``` + /// # use sfml::system::Vector3i; + /// let a = Vector3i::from((1, 2, 3)); + /// assert_eq!(a, Vector3i::new(1, 2, 3)); + /// ``` + fn from(src: (T, T, T)) -> Self { + Self { + x: src.0, + y: src.1, + z: src.2, + } + } +} + +impl From> for (T, T, T) { + /// Constructs `(x, y, z)` from a `Vector3` + fn from(vec: Vector3) -> Self { + (vec.x, vec.y, vec.z) + } +} + +impl From<[T; 3]> for Vector3 { + /// Constructs a `Vector3` from `[x, y, z]`. + fn from([x, y, z]: [T; 3]) -> Self { + Self { x, y, z } + } +} + +impl From> for [T; 3] { + /// Constructs `[x, y, z]` from a `Vector3` + fn from(vec: Vector3) -> Self { + [vec.x, vec.y, vec.z] + } } impl Add for Vector3 { @@ -410,29 +527,6 @@ impl DivAssign for Vector3 { self.z /= rhs; } } - -impl Vector3 { - /// `checked_div` for scalar division - /// - /// # Usage Example - /// - /// ``` - /// # use sfml::system::Vector3i; - /// // Passing case - /// let a = Vector3i::new(10, 10, 10); - /// assert_eq!(a.checked_div(3), Some(Vector3i::new(3, 3, 3))); - /// - /// // Failing case - /// assert_eq!(a.checked_div(0), None); - /// ``` - pub fn checked_div(self, rhs: T) -> Option> { - let x = self.x.checked_div(&rhs)?; - let y = self.y.checked_div(&rhs)?; - let z = self.z.checked_div(&rhs)?; - Some(Vector3 { x, y, z }) - } -} - impl> Neg for Vector3 { type Output = Self; @@ -454,43 +548,3 @@ impl> Neg for Vector3 { } } } - -impl From<(T, T, T)> for Vector3 { - /// Constructs a `Vector3` from `(x, y, z)`. - /// - /// # Usage Example - /// - /// ``` - /// # use sfml::system::Vector3i; - /// let a = Vector3i::from((1, 2, 3)); - /// assert_eq!(a, Vector3i::new(1, 2, 3)); - /// ``` - fn from(src: (T, T, T)) -> Self { - Self { - x: src.0, - y: src.1, - z: src.2, - } - } -} - -impl From> for (T, T, T) { - /// Constructs `(x, y, z)` from a `Vector3` - fn from(vec: Vector3) -> Self { - (vec.x, vec.y, vec.z) - } -} - -impl From<[T; 3]> for Vector3 { - /// Constructs a `Vector3` from `[x, y, z]`. - fn from([x, y, z]: [T; 3]) -> Self { - Self { x, y, z } - } -} - -impl From> for [T; 3] { - /// Constructs `[x, y, z]` from a `Vector3` - fn from(vec: Vector3) -> Self { - [vec.x, vec.y, vec.z] - } -} diff --git a/src/window/context.rs b/src/window/context.rs index 918cd024..3d93f886 100644 --- a/src/window/context.rs +++ b/src/window/context.rs @@ -26,6 +26,15 @@ impl Context { FBox::new(unsafe { ffi::sfContext_new() }).into_sf_result() } + /// Check whether a given OpenGL extension is available. + /// + /// # Arguments + /// name - Name of the extension to check for + #[must_use] + pub fn is_extension_available(name: &CStr) -> bool { + unsafe { ffi::sfContext_isExtensionAvailable(name.as_ptr()) } + } + /// Explicitly activates or deactivates the context. /// /// # Arguments @@ -71,8 +80,14 @@ impl Context { fn test_settings() { use {crate::window::Window, std::thread}; - let window = - Window::new_open((32, 32), "test", Default::default(), &Default::default()).unwrap(); + let window = Window::new_open( + (32, 32), + "test", + Default::default(), + Default::default(), + &Default::default(), + ) + .unwrap(); let win_settings = *window.settings(); thread::spawn(move || { let context = Context::new().unwrap(); diff --git a/src/window/cursor.rs b/src/window/cursor.rs index 03f4f927..6a308e9d 100644 --- a/src/window/cursor.rs +++ b/src/window/cursor.rs @@ -1,7 +1,7 @@ use crate::{ IntoSfResult, SfResult, cpp::FBox, - ffi::window::{self as ffi, sfCursor_loadFromPixels, sfCursor_loadFromSystem, sfCursor_new}, + ffi::window::{self as ffi}, system::Vector2u, }; @@ -33,44 +33,8 @@ impl Drop for Cursor { /// Creation impl Cursor { - /// # Safety - /// - /// Must be inited with [`Self::load_from_pixels`] or [`Self::load_from_system`] - unsafe fn new() -> SfResult> { - FBox::new(unsafe { sfCursor_new() }).into_sf_result() - } /// Create a new `Cursor` from the provided image data. /// - /// See [`Self::load_from_pixels`]. - /// - /// # Safety - /// - /// Also see [`Self::load_from_pixels`]. - pub unsafe fn from_pixels( - pixels: &[u8], - size: Vector2u, - hotspot: Vector2u, - ) -> SfResult> { - unsafe { - let mut new = Self::new()?; - new.load_from_pixels(pixels, size, hotspot)?; - Ok(new) - } - } - /// Create a new `Cursor` from a native system cursor. - pub fn from_system(type_: Type) -> SfResult> { - unsafe { - let mut new = Self::new()?; - new.load_from_system(type_)?; - Ok(new) - } - } -} - -/// Loading -impl Cursor { - /// Load the cursor with the provided image data. - /// /// `pixels` must be an array of width by height pixels in 32-bit RGBA format. /// If not, this will cause undefined behavior. /// @@ -105,15 +69,15 @@ impl Cursor { /// > I noticed that on at least Linux X11, if the size of the image is not a power of 2, /// > the image is loaded in a wrong way that doesn't respect the dimensions. This is also /// > why I decided to leave this function unsafe. - pub unsafe fn load_from_pixels( - &mut self, + pub unsafe fn from_pixels( pixels: &[u8], size: Vector2u, hotspot: Vector2u, - ) -> SfResult<()> { - unsafe { sfCursor_loadFromPixels(self, pixels.as_ptr(), size, hotspot) }.into_sf_result() + ) -> SfResult> { + FBox::new(unsafe { sfCursor_createFromPixels(pixels.as_ptr(), size, hotspot) }) + .into_sf_result() } - /// Load a native system cursor. + /// Create a new `Cursor` from a native system cursor. /// /// Refer to the list of cursor available on each system (see `CursorType`) to /// know whether a given cursor is expected to load successfully or @@ -123,9 +87,11 @@ impl Cursor { /// - `type_`: Native system cursor type /// /// Returns an error if the cursor type is not supported by the operating system. - pub fn load_from_system(&mut self, type_: Type) -> SfResult<()> { - unsafe { sfCursor_loadFromSystem(self, type_) }.into_sf_result() + pub fn from_system(type_: Type) -> SfResult> { + FBox::new(unsafe { sfCursor_createFromSystem(type_) }).into_sf_result() } } pub use ffi::sfCursorType as Type; + +use self::ffi::{sfCursor_createFromPixels, sfCursor_createFromSystem}; diff --git a/src/window/event.rs b/src/window/event.rs index ff380ee4..8aa8a5b7 100644 --- a/src/window/event.rs +++ b/src/window/event.rs @@ -1,4 +1,4 @@ -use crate::ffi::{window as ffi, window::EventType}; +use crate::ffi::window::{self as ffi, EventType}; /// Defines a system event and its parameters. /// @@ -20,15 +20,13 @@ pub enum Event { Closed, /// The window was resized Resized { - /// The new width of the window - width: u32, - /// The new height of the window - height: u32, + /// New size, in pixels + size: ffi::sfVector2u, }, /// The window lost the focus - LostFocus, + FocusLost, /// The window gained the focus - GainedFocus, + FocusGained, /// A character was entered TextEntered { /// The character entered by the user @@ -64,9 +62,6 @@ pub enum Event { /// Is system released too? system: bool, }, - #[doc(hidden)] - /// Do not use. Needed for compatibility with SFML. - MouseWheelMoved, /// The mouse wheel was scrolled MouseWheelScrolled { /// Which wheel (for mice with multiple ones). @@ -74,35 +69,54 @@ pub enum Event { /// Wheel offset (positive is up/left, negative is down/right). /// High-precision mice may use non-integral offsets. delta: f32, - /// X position of the mouse pointer, relative to the left of the owner window. - x: i32, - /// Y position of the mouse pointer, relative to the top of the owner window. - y: i32, + /// Position of the mouse pointer, relative to the top left of the owner window + position: ffi::sfVector2i, }, /// A mouse button was pressed MouseButtonPressed { /// Code of the button that has been pressed. button: ffi::MouseButton, - /// X position of the mouse pointer, relative to the left of the owner window. - x: i32, - /// Y position of the mouse pointer, relative to the top of the owner window. - y: i32, + /// Position of the mouse pointer, relative to the top left of the owner window + position: ffi::sfVector2i, }, /// A mouse button was released MouseButtonReleased { /// Code of the button that has been pressed. button: ffi::MouseButton, - /// X position of the mouse pointer, relative to the left of the owner window. - x: i32, - /// Y position of the mouse pointer, relative to the top of the owner window. - y: i32, + /// Position of the mouse pointer, relative to the top left of the owner window + position: ffi::sfVector2i, }, /// The mouse cursor moved MouseMoved { - /// X position of the mouse pointer, relative to the left of the owner window. - x: i32, - /// Y position of the mouse pointer, relative to the top of the owner window. - y: i32, + /// Position of the mouse pointer, relative to the top left of the owner window + position: ffi::sfVector2i, + }, + /// Raw mouse input data comes unprocessed from the + /// operating system hence "raw". While the `MouseMoved` + /// position value is dependent on the screen resolution, + /// raw data is not. If the physical mouse is moved too + /// little to cause the screen cursor to move at least a + /// single pixel, no `MouseMoved` event will be generated. In + /// contrast, any movement information generated by the + /// mouse independent of its sensor resolution will always + /// generate a `MouseMovedRaw` event. + /// + /// In addition to screen resolution independence, raw + /// mouse data also does not have mouse acceleration or + /// smoothing applied to it as `MouseMoved` does. + /// + /// Raw mouse movement data is intended for controlling + /// non-cursor movement, e.g. controlling the camera + /// orientation in a first person view, whereas `MouseMoved` + /// is intended primarily for controlling things related to + /// the screen cursor hence the additional processing + /// applied to it. + /// + /// Currently, raw mouse input events will only be generated + /// on Windows and Linux. + MouseMovedRaw { + /// Delta movement of the mouse since the last event + delta: ffi::sfVector2i, }, /// The mouse cursor entered the area of the window MouseEntered, @@ -159,58 +173,42 @@ pub enum Event { TouchBegan { /// Index of the finger in case of multi-touch events. finger: u32, - /// X position of the touch, relative to the left of the owner window. - x: i32, - /// Y position of the touch, relative to the top of the owner window. - y: i32, + /// Start position of the touch, relative to the top left of the owner window + position: ffi::sfVector2i, }, /// A touch moved TouchMoved { /// Index of the finger in case of multi-touch events. finger: u32, - /// X position of the touch, relative to the left of the owner window. - x: i32, - /// Y position of the touch, relative to the top of the owner window. - y: i32, + /// Start position of the touch, relative to the top left of the owner window + position: ffi::sfVector2i, }, /// A touch event ended TouchEnded { /// Index of the finger in case of multi-touch events. finger: u32, - /// X position of the touch, relative to the left of the owner window. - x: i32, - /// Y position of the touch, relative to the top of the owner window. - y: i32, + /// Start position of the touch, relative to the top left of the owner window + position: ffi::sfVector2i, }, /// A sensor value changed SensorChanged { /// Type of the sensor. type_: ffi::window::sfSensorType, - /// Current value of the sensor on X axis. - x: f32, - /// Current value of the sensor on Y axis. - y: f32, - /// Current value of the sensor on Z axis. - z: f32, + /// Current value of the sensor on the X, Y, and Z axes + value: ffi::sfVector3f, }, } impl Event { pub(crate) unsafe fn from_raw(event: &ffi::Event) -> Option { use crate::window::Event::*; - let evt = match event.type_ { EventType::Closed => Closed, - EventType::Resized => { - let e = unsafe { event.union.size }; - - Resized { - width: e.width, - height: e.height, - } - } - EventType::LostFocus => LostFocus, - EventType::GainedFocus => GainedFocus, + EventType::Resized => Resized { + size: unsafe { event.union.size.size }, + }, + EventType::FocusLost => FocusLost, + EventType::FocusGained => FocusGained, EventType::TextEntered => TextEntered { unicode: std::char::from_u32(unsafe { event.union.text.unicode }) .expect("Invalid unicode encountered on TextEntered event"), @@ -234,22 +232,21 @@ impl Event { EventType::MouseWheelScrolled => MouseWheelScrolled { wheel: unsafe { event.union.mouse_wheel_scroll.wheel }, delta: unsafe { event.union.mouse_wheel_scroll.delta }, - x: unsafe { event.union.mouse_wheel_scroll.x }, - y: unsafe { event.union.mouse_wheel_scroll.y }, + position: unsafe { event.union.mouse_wheel_scroll.position }, }, EventType::MouseButtonPressed => MouseButtonPressed { button: unsafe { event.union.mouse_button.button }, - x: unsafe { event.union.mouse_button.x }, - y: unsafe { event.union.mouse_button.y }, + position: unsafe { event.union.mouse_button.position }, }, EventType::MouseButtonReleased => MouseButtonReleased { button: unsafe { event.union.mouse_button.button }, - x: unsafe { event.union.mouse_button.x }, - y: unsafe { event.union.mouse_button.y }, + position: unsafe { event.union.mouse_button.position }, }, EventType::MouseMoved => MouseMoved { - x: unsafe { event.union.mouse_move.x }, - y: unsafe { event.union.mouse_move.y }, + position: unsafe { event.union.mouse_button.position }, + }, + EventType::MouseMovedRaw => MouseMovedRaw { + delta: unsafe { event.union.mouse_move_raw.delta }, }, EventType::MouseEntered => MouseEntered, EventType::MouseLeft => MouseLeft, @@ -274,26 +271,20 @@ impl Event { }, EventType::TouchBegan => TouchBegan { finger: unsafe { event.union.touch.finger }, - x: unsafe { event.union.touch.x }, - y: unsafe { event.union.touch.y }, + position: unsafe { event.union.mouse_button.position }, }, EventType::TouchMoved => TouchMoved { finger: unsafe { event.union.touch.finger }, - x: unsafe { event.union.touch.x }, - y: unsafe { event.union.touch.y }, + position: unsafe { event.union.mouse_button.position }, }, EventType::TouchEnded => TouchEnded { finger: unsafe { event.union.touch.finger }, - x: unsafe { event.union.touch.x }, - y: unsafe { event.union.touch.y }, + position: unsafe { event.union.mouse_button.position }, }, EventType::SensorChanged => SensorChanged { type_: unsafe { event.union.sensor.type_ }, - x: unsafe { event.union.sensor.x }, - y: unsafe { event.union.sensor.y }, - z: unsafe { event.union.sensor.z }, + value: unsafe { event.union.sensor.value }, }, - EventType::MouseWheelMoved => Event::MouseWheelMoved, }; Some(evt) } diff --git a/src/window/keyboard.rs b/src/window/keyboard.rs index f2ec3da7..2f8ef2e6 100644 --- a/src/window/keyboard.rs +++ b/src/window/keyboard.rs @@ -1,5 +1,7 @@ pub use crate::ffi::window::Key; -use crate::{ffi::window as ffi, window::thread_safety}; +use crate::{ffi::window as ffi, system::SfStr, window::thread_safety}; + +use super::Scancode; impl Key { /// Return whether this key is currently pressed. @@ -8,13 +10,70 @@ impl Key { /// pressed or released while no window was focused and no events were /// triggered. #[must_use] - pub fn is_pressed(self) -> bool { + pub fn is_key_pressed(self) -> bool { thread_safety::set_window_thread(); unsafe { ffi::sfKeyboard_isKeyPressed(self) } } } +impl From for Key { + fn from(scancode: Scancode) -> Self { + unsafe { ffi::sfKeyboard_localize(scancode) } + } +} + +impl Scancode { + /// Check if a key is pressed + /// + /// Queries the real-time state of the keyboard, even if keys have been + /// pressed or released while no window was focused and no events were + /// triggered. + #[must_use] + pub fn is_scancode_pressed(self) -> bool { + thread_safety::set_window_thread(); + unsafe { ffi::sfKeyboard_isScancodePressed(self) } + } + + /// Provide a string representation for a given scancode + /// + /// The returned string is a short, non-technical description of + /// the key represented with the given scancode. Most effectively + /// used in user interfaces, as the description for the key takes + /// the users keyboard layout into consideration. + /// + /// # Warning + /// The result is OS-dependent: for example, sfScanLSystem + /// is "Left Meta" on Linux, "Left Windows" on Windows and + /// "Left Command" on macOS. + /// + /// The current keyboard layout set by the operating system is used to + /// interpret the scancode: for example, sfKeySemicolon is + /// mapped to ";" for layout and to "é" for others. + /// + /// The returned const char* owns the string and must be freed to + /// avoid memory leaks. + /// + /// # Arguments + /// code - Scancode to describe + #[must_use] + pub fn description(self) -> String { + unsafe { + let sf_string = ffi::sfKeyboard_getDescription(self); + let data = ffi::system::sfString_getData(sf_string); + let string = SfStr::from_ptr_str(data).to_rust_string(); + ffi::system::sfString_delete(sf_string); + string + } + } +} + +impl From for Scancode { + fn from(key: Key) -> Self { + unsafe { ffi::sfKeyboard_delocalize(key) } + } +} + /// Show or hide the virtual keyboard. /// /// Warning: the virtual keyboard is not supported on all systems. It will typically be diff --git a/src/window/mod.rs b/src/window/mod.rs index e58c103c..c3ae5df3 100644 --- a/src/window/mod.rs +++ b/src/window/mod.rs @@ -7,9 +7,9 @@ pub use { cursor::{Cursor, Type as CursorType}, event::Event, keyboard::{Key, set_virtual_keyboard_visible}, - style::Style, video_mode::VideoMode, window::{Handle, Window}, + window_enums::Style, }, crate::ffi::window::Scancode, }; @@ -23,9 +23,9 @@ pub mod joystick; mod keyboard; pub mod mouse; pub mod sensor; -mod style; pub(crate) mod thread_safety; pub mod touch; mod video_mode; #[expect(clippy::module_inception)] mod window; +pub mod window_enums; diff --git a/src/window/sensor.rs b/src/window/sensor.rs index 9041fa1f..ae7aec8f 100644 --- a/src/window/sensor.rs +++ b/src/window/sensor.rs @@ -90,6 +90,4 @@ impl Type { pub const USER_ACCELERATION: Self = Self(sfSensorType::UserAcceleration); /// Measures the absolute 3D orientation (degrees) pub const ORIENTATION: Self = Self(sfSensorType::Orientation); - /// The total number of sensor types. - pub const COUNT: sfSensorType = sfSensorType::Count; } diff --git a/src/window/video_mode.rs b/src/window/video_mode.rs index c9da72c9..7ccc8947 100644 --- a/src/window/video_mode.rs +++ b/src/window/video_mode.rs @@ -1,6 +1,7 @@ use crate::{ cpp::{CppVector, CppVectorItem}, ffi::window as ffi, + system::{Vector2, Vector2u}, window::thread_safety, }; @@ -24,12 +25,10 @@ use crate::{ /// the desktop: [`VideoMode::desktop_mode`]. This allows to build windows with the same size or /// pixel depth as the current resolution. #[repr(C)] -#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Debug)] +#[derive(Clone, Copy, PartialEq, Eq, Debug)] pub struct VideoMode { - /// Video mode width, in pixels - pub width: std::ffi::c_uint, - /// Video mode height, in pixels - pub height: std::ffi::c_uint, + /// Video mode size, in pixels + pub size: Vector2, /// Video mode pixel depth, in bits per pixels pub bits_per_pixel: std::ffi::c_uint, } @@ -37,10 +36,9 @@ pub struct VideoMode { impl VideoMode { /// Constructs a new `VideoMode` from the given parameters. #[must_use] - pub const fn new(width: u32, height: u32, bits_per_pixel: u32) -> Self { + pub const fn new(size: Vector2u, bits_per_pixel: u32) -> Self { Self { - width, - height, + size, bits_per_pixel, } } @@ -84,23 +82,30 @@ impl VideoMode { } } -impl From<(u32, u32)> for VideoMode { - /// Constructs a `VideoMode` from `(w, h)`. Bit depth is 32. - fn from((w, h): (u32, u32)) -> Self { - Self::new(w, h, 32) +impl From for VideoMode { + /// Constructs a `VideoMode` from `Vector2`. Bit depth is 32. + fn from(size: Vector2u) -> Self { + Self::new(size, 32) } } impl From<[u32; 2]> for VideoMode { /// Constructs a `VideoMode` from `[w, h]`. Bit depth is 32. fn from([w, h]: [u32; 2]) -> Self { - Self::new(w, h, 32) + Self::new(Vector2::new(w, h), 32) + } +} + +impl From<(u32, u32)> for VideoMode { + /// Constructs a `VideoMode` from `(w, h)`. Bit depth is 32. + fn from(size: (u32, u32)) -> Self { + Self::new(size.into(), 32) } } impl Default for VideoMode { fn default() -> Self { - Self::new(0, 0, 0) + Self::new(Vector2::new(0, 0), 0) } } diff --git a/src/window/window.rs b/src/window/window.rs index 44a6a291..ade295c1 100644 --- a/src/window/window.rs +++ b/src/window/window.rs @@ -2,10 +2,12 @@ use crate::{ IntoSfResult, SfResult, cpp::FBox, ffi::window as ffi, - system::{SfStrConv, Vector2i, Vector2u}, + system::{SfStrConv, Time, Vector2i, Vector2u}, window::{ContextSettings, Cursor, Event, Style, VideoMode, thread_safety}, }; +use super::window_enums::State; + /// The system native window handle type. Can be used to create an SFML Window /// from an existing system window. pub type Handle = ffi::sfWindowHandle; @@ -40,10 +42,11 @@ impl Window { mode: V, title: S, style: Style, + state: State, settings: &ContextSettings, ) -> SfResult> { let mut new = Self::new()?; - new.open(mode, title, style, settings); + new.open(mode, title, style, state, settings); Ok(new) } /// Open the window with the specified parameters @@ -69,11 +72,19 @@ impl Window { mode: V, title: S, style: Style, + state: State, settings: &ContextSettings, ) { thread_safety::set_window_thread(); title.with_as_sfstr(|sfstr| unsafe { - ffi::sfWindow_create_mtss(self, mode.into(), sfstr.as_ptr(), style.bits(), settings) + ffi::sfWindow_create_mtsss( + self, + mode.into(), + sfstr.as_ptr(), + style.bits(), + state, + settings, + ) }) } @@ -106,7 +117,7 @@ impl Window { /// doesn't support, or implement a temporary workaround until a bug is fixed. #[must_use] pub fn system_handle(&self) -> Handle { - unsafe { ffi::sfWindow_getSystemHandle(self) } + unsafe { ffi::sfWindow_getNativeHandle(self) } } /// Pop the event on top of event queue, if any, and return it @@ -138,9 +149,10 @@ impl Window { /// sleep as long as no new event is received. /// /// Returns `Some(event)` or `None` if an error has occured - pub fn wait_event(&mut self) -> Option { + pub fn wait_event(&mut self, timeout: Time) -> Option { let mut event = std::mem::MaybeUninit::uninit(); - let have_event = unsafe { ffi::sfWindow_waitEvent(self, event.as_mut_ptr()) }; + let have_event = + unsafe { ffi::sfWindow_waitEvent(self, event.as_mut_ptr(), timeout.as_microseconds()) }; if have_event { unsafe { Event::from_raw(&event.assume_init()) } } else { @@ -152,8 +164,7 @@ impl Window { /// pixels must be an array of width x height pixels in 32-bits RGBA format. /// /// # Arguments - /// * width - Icon's width, in pixels - /// * height - Icon's height, in pixels + /// * size - Size of window /// * pixels - Vector of pixels /// /// # Safety @@ -161,8 +172,8 @@ impl Window { /// `pixels` not being at least `width * height * 4` will likely cause undefined behavior. /// /// Platform-specific behavior is also unclear (limits on max size, etc). - pub unsafe fn set_icon(&mut self, width: u32, height: u32, pixels: &[u8]) { - unsafe { ffi::sfWindow_setIcon(self, width, height, pixels.as_ptr()) } + pub unsafe fn set_icon(&mut self, size: Vector2u, pixels: &[u8]) { + unsafe { ffi::sfWindow_setIcon(self, size, pixels.as_ptr()) } } /// Close a window and destroy all the attached resources @@ -206,7 +217,11 @@ impl Window { /// # Arguments /// * title - New title pub fn set_title(&mut self, title: S) { - title.with_as_sfstr(|sfstr| unsafe { ffi::sfWindow_setUnicodeTitle(self, sfstr.as_ptr()) }) + unsafe { + title.with_as_sfstr(|sfstr| { + ffi::sfWindow_setUnicodeTitle(self, sfstr.as_ptr()); + }); + } } /// Show or hide a window @@ -346,6 +361,26 @@ impl Window { unsafe { ffi::sfWindow_setSize(self, size) } } + /// Set the minimum rendering region size + /// + /// Pass `None` to unset the minimum size + pub fn set_minimum_size(&mut self, size: Option) { + let ptr = size.as_ref().map_or(std::ptr::null(), |v| v); + unsafe { + ffi::sfWindow_setMinimumSize(self, ptr); + } + } + + /// Set the maximum rendering region size + /// + /// Pass `None` to unset the maximum size + pub fn set_maximum_size(&mut self, size: Option) { + let ptr = size.as_ref().map_or(std::ptr::null(), |v| v); + unsafe { + ffi::sfWindow_setMaximumSize(self, ptr); + } + } + /// Returns the current position of the mouse relative to the window. #[must_use] pub fn mouse_position(&self) -> Vector2i { diff --git a/src/window/style.rs b/src/window/window_enums.rs similarity index 79% rename from src/window/style.rs rename to src/window/window_enums.rs index 6b08414a..de535dd8 100644 --- a/src/window/style.rs +++ b/src/window/window_enums.rs @@ -26,3 +26,14 @@ impl Default for Style { Self::DEFAULT } } + +#[repr(C)] +#[derive(Clone, Copy, PartialEq, Eq, Debug, Default)] +/// Available window state of your window +pub enum State { + #[default] + /// Windowed mode + Windowed, + /// Fullscreen mode + Fullscreen, +}