added function to disable audio chunks, colors default to fully transparent, add public getters for Pad::box and Pad::visible

This commit is contained in:
ohsqueezy 2024-05-01 20:25:35 -04:00
parent 8498dfa004
commit 102d1749a5
15 changed files with 244 additions and 153 deletions

View File

@ -5,7 +5,7 @@
/\ +-------------------------------------------------------+
____/ \____ /| Open source game framework licensed to freely use, |
\ / / | copy, and modify. Created for [dank.game] |
\ / / | copy, and modify, created for dank.game |
+--\ ^__^ /--+ | |
| ~/ \~ | | Download at https://open.shampoo.ooo/shampoo/spacebox |
| ~~~~~~~~~~~~ | +-------------------------------------------------------+
@ -577,11 +577,11 @@ When initializing a Game object, the framework will attempt to load the font fil
License
-------
[SPACEBOX] is released under the zlib license. It is free to use, copy, modify and sell. See LICENSE.txt for details.
SPACE🪐BOX is released under the zlib license. It is free to use, copy, modify and sell. See [LICENSE.txt](LICENSE.txt) for details.
Included libraries are included under various permissive licenses compatible with the zlib license:
* BPmono.ttf is licensed under the Creative Commons Attribution * No Derivative Works 3.0 license. See [LICENSE_BPmono.txt]()
* BPmono.ttf is licensed under the Creative Commons Attribution, No Derivative Works 3.0 license. See [LICENSE_BPmono.txt]()
* gif-h is unlicensed, public domain code released under the The Unlicense. See [lib/gif-h/LICENSE]()
* GLEW is included under the license in [lib/glew/LICENSE.txt]()
* GLM is included under the MIT license in [lib/glm/LICENSE]()
@ -592,8 +592,12 @@ Included libraries are included under various permissive licenses compatible wit
Contact
-------
mailbox at shampoo.ooo
https://twitter.com/diskmem
| Method | Contact information |
| :------ | :---------------------------- |
| E-mail | cocktail.frank@dank.game |
| Web | <https://dank.game> |
| X | <https://x.com/diskmem> |
| PayPal | <https://paypal.me/ohsqueezy> |
[SDL wiki Android page]: https://wiki.libsdl.org/Android
[SDL docs Android README]: https://github.com/libsdl-org/SDL/blob/main/docs/README-android.md

View File

@ -1,3 +1,13 @@
/* +------------------------------------------------------+
____/ \____ /| - Open source game framework licensed to freely use, |
\ / / | copy, modify and sell without restriction |
+--\ ^__^ /--+ | |
| ~/ \~ | | - created for <https://foam.shampoo.ooo> |
| ~~~~~~~~~~~~ | +------------------------------------------------------+
| SPACE ~~~~~ | /
| ~~~~~~~ BOX |/
+-------------*/
#include "Audio.hpp"
using namespace sb::audio;
@ -101,29 +111,36 @@ void Chunk::loop(int count)
int Chunk::play(float fade, int channel)
{
/* Play the audio with a fade in time if any was specified. */
int assignment;
if (fade <= 0.0f)
if (enabled())
{
assignment = Mix_PlayChannel(channel, chunk.get(), loops);
/* Play the audio with a fade in time if any was specified. */
int assignment;
if (fade <= 0.0f)
{
assignment = Mix_PlayChannel(channel, chunk.get(), loops);
}
else
{
int milliseconds = static_cast<int>(std::round(fade * 1000.0f));
assignment = Mix_FadeInChannel(channel, chunk.get(), loops, milliseconds);
}
/* Check if the audio is paused on other channels. If so, stop the audio on those channels. */
int count = Mix_GroupCount(-1);
for (int index = 0; index < count; index++)
{
if (index != assignment && Mix_GetChunk(index) == chunk.get() && Mix_Paused(index))
{
Mix_HaltChannel(index);
}
}
return assignment;
}
else
{
int milliseconds = static_cast<int>(std::round(fade * 1000.0f));
assignment = Mix_FadeInChannel(channel, chunk.get(), loops, milliseconds);
return -1;
}
/* Check if the audio is paused on other channels. If so, stop the audio on those channels. */
int count = Mix_GroupCount(-1);
for (int index = 0; index < count; index++)
{
if (index != assignment && Mix_GetChunk(index) == chunk.get() && Mix_Paused(index))
{
Mix_HaltChannel(index);
}
}
return assignment;
}
void Chunk::stop(float fade)
@ -160,12 +177,15 @@ void Chunk::pause()
void Chunk::resume()
{
int count = Mix_GroupCount(-1);
for (int channel = 0; channel < count; channel++)
if (enabled())
{
if (Mix_GetChunk(channel) == chunk.get())
int count = Mix_GroupCount(-1);
for (int channel = 0; channel < count; channel++)
{
Mix_Resume(channel);
if (Mix_GetChunk(channel) == chunk.get())
{
Mix_Resume(channel);
}
}
}
}
@ -209,6 +229,15 @@ bool Chunk::fading() const
return false;
}
bool Chunk::enabled(std::optional<bool> state)
{
if (state.has_value())
{
_enabled = state.value();
}
return _enabled;
}
Music::Music(const fs::path& path)
{
load(path);

View File

@ -1,9 +1,9 @@
/* +------------------------------------------------------+
____/ \____ /| - Open source game framework licensed to freely use, |
\ / / | copy, modify and sell without restriction |
+--\ ^__^ /--+ | |
| ~/ \~ | | - created for <https://foam.shampoo.ooo> |
| ~~~~~~~~~~~~ | +------------------------------------------------------+
/* +-------------------------------------------------------+
____/ \____ /| Open source game framework licensed to freely use, |
\ / / | copy, and modify, created for dank.game |
+--\ ^__^ /--+ | |
| ~/ \~ | | Download at https://open.shampoo.ooo/shampoo/spacebox |
| ~~~~~~~~~~~~ | +-------------------------------------------------------+
| SPACE ~~~~~ | /
| ~~~~~~~ BOX |/
+-------------*/
@ -15,6 +15,7 @@
#include <functional>
#include <algorithm>
#include <cmath>
#include <optional>
#include "SDL.h"
#include "SDL_mixer.h"
#include "filesystem.hpp"
@ -52,12 +53,13 @@ namespace sb::audio
/*!
* Load audio from an OGG or WAV file and play it.
*
* Each instance contains an SDL `Mix_Chunk` audio data struct and automatically finds a open channel to play it on when play is requested. The chunk
* can be playing on multiple channels simultaneously.
* Each instance contains an SDL `Mix_Chunk` audio data struct and automatically finds a open channel to play it on when play is
* requested. The chunk can be playing on multiple channels simultaneously.
*
* There are some differences between how `Mix_Chunk` and `Mix_Music` can be used with the API, most notably that multiple chunks can be playing on
* multiple channels simultaneously, but only one music object can be playing at a time. This is most likely because `Mix_Music` objects are streamed
* and `Mix_Chunk` are loaded into memory, but I haven't verified that by looking at the internal code.
* There are some differences between how `Mix_Chunk` and `Mix_Music` can be used with the API, most notably that multiple chunks
* can be playing on multiple channels simultaneously, but only one music object can be playing at a time. This is most likely
* because `Mix_Music` objects are streamed and `Mix_Chunk` are loaded into memory, but I haven't verified that by looking at SDL's
* code.
*/
class Chunk
{
@ -65,6 +67,7 @@ namespace sb::audio
private:
std::shared_ptr<Mix_Chunk> chunk;
bool _enabled = true;
/* -1 means loop forever, any other value is the number of times to loop */
int loops = 0;
@ -77,8 +80,8 @@ namespace sb::audio
Chunk() = default;
/*!
* Create an audio chunk and load it with data from an OGG or WAV file at the given path. If the given path does not contain loadable data,
* a warning will be printed, and an empty chunk will be created.
* Create an audio chunk and load it with data from an OGG or WAV file at the given path. If the given path does not contain
* loadable data, a warning will be printed, and an empty chunk will be created.
*
* This will call Chunk::load(const fs::path&) automatically.
*
@ -87,8 +90,8 @@ namespace sb::audio
Chunk(const fs::path& path);
/*!
* Load audio data from an OGG or WAV file at the given path, replacing any existing audio data in this object. If the given path does not contain
* loadable data, a warning will be printed, and existing audio data will not be overwritten.
* Load audio data from an OGG or WAV file at the given path, replacing any existing audio data in this object. If the given
* path does not contain loadable data, a warning will be printed, and existing audio data will not be overwritten.
*
* @param path path to an OGG or WAV file
*/
@ -105,7 +108,8 @@ namespace sb::audio
void volume(float level);
/*!
* Set the volume of all channels currently playing the audio chunk to a given level. This does not modify the volume of the chunk itself.
* Set the volume of all channels currently playing the audio chunk to a given level. This does not modify the volume of the
* chunk itself.
*
* @param level Volume between 0.0 and 1.0
*/
@ -122,14 +126,15 @@ namespace sb::audio
void loop(int count);
/*!
* Play the audio data loaded into this object once on the first available free channel. Optionally fade in playback over a given amount of time
* in seconds.
* Play the audio data loaded into this object once on the first available free channel. Optionally fade in playback over a
* given amount of time in seconds. If chunk has been disabled using `Chunk::enabled(bool)`, do nothing instead, and return
* -1.
*
* This always plays the audio from the beginning even if the audio is paused. To resume instead, use Chunk::resume(). Any audio chunks currently
* paused will be stopped.
* This always plays the audio from the beginning even if the audio is paused. To resume instead, use Chunk::resume(). Any
* audio chunks currently paused will be stopped.
*
* If the audio is playing already, however, it will continue to play on that channel, and it will be played again from the beginning on another
* channel.
* If the audio is playing already, however, it will continue to play on that channel, and it will be played again from the
* beginning on another channel.
*
* @param fade Length of fade in in seconds
* @param channel The SDL mixer channel to play the sound on. A value of -1 means choose a channel automatically.
@ -138,7 +143,8 @@ namespace sb::audio
int play(float fade = 0.0f, int channel = -1);
/*!
* Stop playback of this audio chunk on all channels it is playing on. Optionally fade out over the given amount of time in seconds.
* Stop playback of this audio chunk on all channels it is playing on. Optionally fade out over the given amount of time in
* seconds.
*
* @param fade length of fade out in seconds
*/
@ -155,7 +161,8 @@ namespace sb::audio
void resume();
/*!
* @return True if the audio is playing on any channel, false otherwise. Note that paused or fading audio is considered playing.
* @return True if the audio is playing on any channel, false otherwise. Note that paused or fading audio is considered
* playing.
*/
bool playing() const;
@ -168,16 +175,26 @@ namespace sb::audio
* @return True if the audio is fading in or out on any channels, false otherwise.
*/
bool fading() const;
/*!
* By default, a chunk object is enabled to play audio. If the chunk is disabled, however, the play function will not
* be able to be used. This function can be used both to check the state and to set the state.
*
* @param state Set to false to disable, true to enable, or omit to check the current state
* @return True if button is set to enabled
*/
bool enabled(std::optional<bool> state = std::nullopt);
};
/*!
* Load audio from an OGG or WAV file and play it on a single channel dedicated to music. Only one music object can be playing at a time.
* Load audio from an OGG or WAV file and play it on a single channel dedicated to music. Only one music object can be playing
* at a time.
*
* This class interfaces with SDL mixer's API and Mix_Music audio data pointer.
*
* There are some differences between how Mix_Chunk and Mix_Music can be used with the API, most notably that multiple chunks can be playing on
* multiple channels simultaneously, but only one music object can be playing at a time. This is most likely because Mix_Music objects are streamed
* and Mix_Chunk are loaded into memory, but I haven't verified that by looking at the internal code.
* There are some differences between how Mix_Chunk and Mix_Music can be used with the API, most notably that multiple chunks can
* be playing on multiple channels simultaneously, but only one music object can be playing at a time. This is most likely because
* Mix_Music objects are streamed and Mix_Chunk are loaded into memory, but I haven't verified that by looking at the internal code.
*/
class Music
{

View File

@ -1,16 +1,16 @@
/* +------------------------------------------------------+
____/ \____ /| - Open source game framework licensed to freely use, |
\ / / | copy, modify and sell without restriction |
+--\ ^__^ /--+ | |
| ~/ \~ | | - created for <https://foam.shampoo.ooo> |
| ~~~~~~~~~~~~ | +------------------------------------------------------+
/* +-------------------------------------------------------+
____/ \____ /| Open source game framework licensed to freely use, |
\ / / | copy, and modify, created for dank.game |
+--\ ^__^ /--+ | |
| ~/ \~ | | Download at https://open.shampoo.ooo/shampoo/spacebox |
| ~~~~~~~~~~~~ | +-------------------------------------------------------+
| SPACE ~~~~~ | /
| ~~~~~~~ BOX |/
+-------------*/
#include "Color.hpp"
sb::Color::Color() : sb::Color(0, 0, 0, 255) {}
sb::Color::Color() : sb::Color(0, 0, 0, 0) {}
sb::Color::Color(const SDL_Color& color) : sb::Color(color.r, color.g, color.b, color.a) {};

View File

@ -1,9 +1,9 @@
/* +------------------------------------------------------+
____/ \____ /| - Open source game framework licensed to freely use, |
\ / / | copy, modify and sell without restriction |
+--\ ^__^ /--+ | |
| ~/ \~ | | - created for <https://foam.ooo> |
| ~~~~~~~~~~~~ | +------------------------------------------------------+
/* +-------------------------------------------------------+
____/ \____ /| Open source game framework licensed to freely use, |
\ / / | copy, and modify, created for dank.game |
+--\ ^__^ /--+ | |
| ~/ \~ | | Download at https://open.shampoo.ooo/shampoo/spacebox |
| ~~~~~~~~~~~~ | +-------------------------------------------------------+
| SPACE ~~~~~ | /
| ~~~~~~~ BOX |/
+-------------*/

View File

@ -10,7 +10,7 @@
#include "Configuration.hpp"
Configuration::Configuration(Node* parent) : Node(parent)
Configuration::Configuration()
{
set_defaults();
}

View File

@ -21,12 +21,11 @@
/* SPACEBOX */
#include "filesystem.hpp"
#include "Node.hpp"
#include "Animation.hpp"
#include "Log.hpp"
#include "extension.hpp"
class Configuration : public Node
class Configuration
{
private:
@ -36,10 +35,10 @@ private:
std::vector<fs::path> files_to_refresh;
/*!
* @warning This JSON will be copied when the object is copied, and it is potentially a large copy because it can copy an arbitrary amount of
* JSON data. Because a game object by definition has a single configuration, this can be optimized in the future so that the JSON is stored
* in a member of the game object. Arguably it also doesn't make sense to be copying the data because the JSON is expected to change during
* runtime.
* @warning This JSON will be copied when the object is copied, and it is potentially a large copy because it can copy an arbitrary
* amount of JSON data. Because a game object by definition has a single configuration, this can be optimized in the future so that
* the JSON is stored in a member of the game object. Arguably it also doesn't make sense to be copying the data because the JSON is
* expected to change during runtime.
*/
nlohmann::json config;
@ -91,10 +90,8 @@ public:
* Construct a Configuration object. The path argument is the location to look for a user configuration. If valid JSON is found,
* it will be merged into the hard-coded default assignments, overwriting any existing key/value pairs. The path will be watched
* for changes if auto refresh is turned on.
*
* @param parent SPACEBOX Node rooted at the Game object
*/
Configuration(Node* parent);
Configuration();
/*!
* Get a writable JSON object corresponding to a key in the configuration.
@ -127,13 +124,14 @@ public:
* Example,
*
* std::cout << _configuration() << std::endl;
* std::cout << _configuration("recording", "enabled") << " " << _configuration("input") << " " << _configuration("levels", 0, 3, 1) << std::endl;
* std::cout << _configuration("recording", "enabled") << " " << _configuration("input") << " " <<
* _configuration("levels", 0, 3, 1) << std::endl;
*
* Prints,
*
* [full config...]
* true {"any-key-ignore-commands":[],"default-unsuppress-delay":0.7,"ignore-repeat-keypress":true,"suppress-any-key-on-mods":true, \
* "system-any-key-ignore-commands":["fullscreen","screenshot","record","quit"]} 261.0
* true {"any-key-ignore-commands":[],"default-unsuppress-delay":0.7,"ignore-repeat-keypress":true,\
* "suppress-any-key-on-mods":true, "system-any-key-ignore-commands":["fullscreen","screenshot","record","quit"]} 261.0
*
* @param keys hierarchy of keys used to look up a specific JSON object in the config
* @return read-only reference to JSON object specified by keys

View File

@ -74,9 +74,8 @@ bool Delegate::compare(SDL_Event& event, const std::vector<std::string>& command
bool Delegate::compare(SDL_Event& event, const std::string& command, bool neutral, bool cancel)
{
return event.type == command_event_type &&
(command == "" || command == get_event_command(event)) &&
(neutral || (cancel == get_event_cancel_state(event)));
return event.type == command_event_type && (command == "" || command == event_command(event)) &&
(neutral || (cancel == event_cancel_state(event)));
}
bool Delegate::compare_cancel(SDL_Event& event, const std::string& command)
@ -94,12 +93,12 @@ void Delegate::cancel_propagation()
cancelling_propagation = true;
}
const std::string& Delegate::get_event_command(SDL_Event& event)
const std::string& Delegate::event_command(SDL_Event& event)
{
return *static_cast<std::string*>(event.user.data1);
}
bool Delegate::get_event_cancel_state(SDL_Event& event)
bool Delegate::event_cancel_state(SDL_Event& event)
{
return *static_cast<bool*>(event.user.data2);
}

View File

@ -47,8 +47,8 @@ namespace sb
static bool compare_cancel(SDL_Event&, const std::string& = "");
static bool compare_neutral(SDL_Event&, const std::string& = "");
void cancel_propagation();
static const std::string& get_event_command(SDL_Event&);
static bool get_event_cancel_state(SDL_Event&);
static const std::string& event_command(SDL_Event&);
static bool event_cancel_state(SDL_Event&);
/*!
* Post a custom command to the queue. There is not currently support for passing custom data along with the command. The string

View File

@ -77,7 +77,7 @@ private:
protected:
Configuration _configuration {this};
Configuration _configuration;
public:

View File

@ -37,13 +37,13 @@ namespace sb
* this object is copied, its textures are copied with reference to the same GPU memory preserved. */
std::vector<sb::Texture> _textures;
/* The attributes are associated with vertex data copied on the GPU. Shared pointers are used to store the attributes, so that if a
* copy of this object is made, each attributes in the copied object will point to its originally constructed attributes object, preserving
* the association with the vertex data on the GPU. */
/* The attributes are associated with vertex data copied on the GPU. Shared pointers are used to store the attributes, so that if
* a copy of this object is made, each attributes in the copied object will point to its originally constructed attributes object,
* preserving the association with the vertex data on the GPU. */
std::map<std::string, std::shared_ptr<sb::Attributes>> _attributes;
/* The model keeps a single transformation matrix. Specific types of transformation, like scale, translate, etc, can be combined into this
* transformation. */
/* The model keeps a single transformation matrix. Specific types of transformation, like scale, translate, etc, can be combined
* into this transformation. */
glm::mat4 _transformation {1.0f};
public:
@ -173,25 +173,28 @@ namespace sb
std::vector<sb::Texture>& textures();
/*!
* Get a constant reference to the texture at the given index. If there are no textures, an exception will be thrown. If the index is greater
* than the number of textures or is a negative number, modulus will be be used to wrap the value of the index to the size of the texture
* list.
* Get a constant reference to the texture at the given index. If there are no textures, an exception will be thrown. If the
* index is greater than the number of textures or is a negative number, modulus will be be used to wrap the value of the index
* to the size of the texture list.
*
* @param index index of texture to get
*/
const sb::Texture& texture(int index) const;
/*!
* Get the texture at the given index. If there are no textures, an exception will be thrown. If the index is greater than the number of textures
* or is a negative number, modulus will be be used to wrap the value of the index to the size of the texture list.
* Get the texture at the given index. If there are no textures, an exception will be thrown. If the index is greater than the
* number of textures or is a negative number, modulus will be be used to wrap the value of the index to the size of the texture
* list.
*
* @param index index of texture to get
*/
sb::Texture& texture(int index);
/*!
* Add a copy of the given texture to model's list of textures. Note that the texture object is copied, but the texture data is not copied.
* The texture data is stored as a shared pointer in the texture object, so only the pointer is copied.
* Add a copy of the given texture to model's list of textures.
*
* Note: the texture object is copied, but the texture data is not copied. The texture data is stored as a shared pointer in the
* texture object, so only the pointer is copied.
*
* @param texture texture to add to model
*/
@ -216,20 +219,20 @@ namespace sb
void add(sb::VBO& vbo);
/*!
* Bind all of this model's textures by calling each of their bind methods. Textures must already have GL indices set, for example by
* calling Texture::generate() on each.
* Bind all of this model's textures by calling each of their bind methods. Textures must already have GL indices set, for
* example by calling Texture::generate() on each.
*/
virtual void bind_textures() const;
/*!
* Bind all of this model's attributes by calling each of their bind methods. Attributes must already have GL indices set, for example
* by calling Attributes::index(GLint) on each.
* Bind all of this model's attributes by calling each of their bind methods. Attributes must already have GL indices set, for
* example by calling Attributes::index(GLint) on each.
*/
virtual void bind_attributes() const;
/*!
* Bind all of this model's attributes and textures by calling each of their bind methods. Textures and attributes all must already
* have GL indices set, for example by calling Texture::generate() and Attributes::index(GLint) on each.
* Bind all of this model's attributes and textures by calling each of their bind methods. Textures and attributes all must
* already have GL indices set, for example by calling Texture::generate() and Attributes::index(GLint) on each.
*/
virtual void bind() const;

View File

@ -1,9 +1,9 @@
/* +------------------------------------------------------+
____/ \____ /| - Open source game framework licensed to freely use, |
\ / / | copy, modify and sell without restriction |
+--\ ^__^ /--+ | |
| ~/ \~ | | - created for <https://foam.shampoo.ooo> |
| ~~~~~~~~~~~~ | +------------------------------------------------------+
/* +-------------------------------------------------------+
____/ \____ /| Open source game framework licensed to freely use, |
\ / / | copy, and modify, created for dank.game |
+--\ ^__^ /--+ | |
| ~/ \~ | | Download at https://open.shampoo.ooo/shampoo/spacebox |
| ~~~~~~~~~~~~ | +-------------------------------------------------------+
| SPACE ~~~~~ | /
| ~~~~~~~ BOX |/
+-------------*/
@ -19,8 +19,8 @@
namespace sb
{
/*!
* A Pad is an object containing an sb::Plane which can be clicked to launch an arbitrary user function. It can be sized and placed by setting its
* translation and scale values.
* A Pad is an object containing an sb::Plane which can be clicked to launch an arbitrary user function. It can be sized and placed
* by setting its translation and scale values.
*
* Each instance:
*
@ -30,8 +30,8 @@ namespace sb
*
* Example:
*
* glm::vec3 w = glm::mat3({{1, 0, 0}, {0, 1, 0}, {-0.6739, -0.74, 1}}) * glm::mat3({{.1, 0, 0}, {0, .1 * (460.0 / 768.0), 0}, {0, 0, 1}}) *
* glm::vec3({-1, -1, 1});
* glm::vec3 w = glm::mat3({{1, 0, 0}, {0, 1, 0}, {-0.6739, -0.74, 1}}) * glm::mat3({{.1, 0, 0}, {0, .1 * (460.0 / 768.0), 0}, \
* {0, 0, 1}}) * glm::vec3({-1, -1, 1});
* std::cout << w << std::endl << glm::translate(glm::vec3{-0.6739, -0.74, 0}) *
* glm::scale(glm::vec3{.1, .1 * (460.0 / 768.0), 1}) * glm::vec4{-1, -1, 0, 1} << std::endl;
* Pad p {background.current(), {-0.6739f, -0.74f}, 0.1f, get_display().window_box().aspect(), std::function<void()>()};
@ -49,7 +49,7 @@ namespace sb
using Reaction = std::function<ReturnType(bool, Arguments...)>;
sb::Switch<ReturnType, Arguments...> connection;
sb::Plane _plane;
Box box;
Box _box;
int texture_index = 0;
bool _enabled = true, _visible = true;
@ -60,17 +60,17 @@ namespace sb
*
* @see Pad(sb::Plane, const glm::vec2&, float, float, Reaction, float)
*/
Pad(const glm::vec2& translation = {0.0f, 0.0f}, float scale = 1.0f, float ratio = 1.0f, Reaction on_state_change = Reaction(), float rotation = 0.0f) :
Pad(sb::Plane(), translation, scale, ratio, on_state_change, rotation) {}
Pad(const glm::vec2& translation = {0.0f, 0.0f}, float scale = 1.0f, float ratio = 1.0f, Reaction on_state_change = Reaction(),
float rotation = 0.0f) : Pad(sb::Plane(), translation, scale, ratio, on_state_change, rotation) {}
/*!
* Construct a pad object from an sb::Plane, a translation amount, a scale factor, and a reaction function. The translation is relative
* to (0.0, 0.0), and the scale is relative to the plane object.
* Construct a pad object from an sb::Plane, a translation amount, a scale factor, and a reaction function. The translation is
* relative to (0.0, 0.0), and the scale is relative to the plane object.
*
* The reaction function must accept a boolean as its first argument, which will be given the state of the pad object's switch.
*
* The plane object will be copied into the pad, so any edits must be made before constructing the pad, unless there is a Pad function
* that applies the edit, such as Pad::scale(float, float).
* The plane object will be copied into the pad, so any edits must be made before constructing the pad, unless there is a Pad
* function that applies the edit, such as Pad::scale(float, float).
*
* @param plane plane or plane derivative to represent the pad visually
* @param translation x, y amount to translate the position
@ -82,7 +82,7 @@ namespace sb
Pad(const sb::Plane& plane, glm::vec2 translation = {0.0f, 0.0f}, float scale = 1.0f, float ratio = 1.0f,
Reaction on_state_change = Reaction(), float rotation = 0.0f) : _plane(plane)
{
box.size({2.0f, 2.0f}, true);
_box.size({2.0f, 2.0f}, true);
if (translation != glm::vec2{0.0f, 0.0f})
{
this->translate(translation);
@ -116,6 +116,14 @@ namespace sb
return _plane;
}
/*!
* @return Constant reference to the pad's box object
*/
const sb::Box& box() const
{
return _box;
}
/*!
* Rotate the pad around its center by 90 degrees. If a count is given, rotate by 90 degrees that many times, so for example,
* a count of 3 will be a 270 degree rotation. If the count is negative, rotate -90 degrees.
@ -149,8 +157,8 @@ namespace sb
{
scale.y *= ratio;
}
box.size({2.0f, 2.0f}, true);
box.scale({scale.x, scale.y}, true);
_box.size({2.0f, 2.0f}, true);
_box.scale({scale.x, scale.y}, true);
return _plane.scale(scale);
}
@ -161,8 +169,8 @@ namespace sb
*/
const glm::mat4& translate(const glm::vec2& translation)
{
box.center({0.0f, 0.0f});
box.move(translation);
_box.center({0.0f, 0.0f});
_box.move(translation);
return _plane.translate({translation.x, translation.y, 0.0f});
}
@ -199,7 +207,7 @@ namespace sb
std::vector<glm::vec3> corners;
/* Transform each of the corners into NDC coordinates */
for (const glm::vec2& vertex : {box.sw(), box.nw(), box.ne(), box.se()})
for (const glm::vec2& vertex : {_box.sw(), _box.nw(), _box.ne(), _box.se()})
{
corners.push_back(sb::world_to_ndc(vertex, projection * view));
}
@ -223,7 +231,8 @@ namespace sb
* @param projection projection matrix for transforming from camera space to clip space
* @param texture_flag_uniform uniform ID for boolean enabling or disabling texture display
*/
void draw(GLuint transformation_uniform, glm::mat4 view, glm::mat4 projection, std::optional<GLuint> texture_flag_uniform = std::nullopt)
void draw(GLuint transformation_uniform, glm::mat4 view, glm::mat4 projection,
std::optional<GLuint> texture_flag_uniform = std::nullopt)
{
if (_visible)
{
@ -234,8 +243,8 @@ namespace sb
glUniform1i(texture_flag_uniform.value(), true);
}
/* Determine texture index by checking the state of the pad and the amount of available textures. If there is more than 1 texture,
* the texture will correspond with the state. */
/* Determine texture index by checking the state of the pad and the amount of available textures. If there is more
* than 1 texture, the texture will correspond with the state. */
if (connection && _plane.textures().size() > 1)
{
texture_index = 1;
@ -269,7 +278,8 @@ namespace sb
{
if (!_enabled)
{
throw std::runtime_error("The pad cannot be pressed because it is currently disabled. Please check Pad::enabled before calling Pad::press.");
throw std::runtime_error(
"The pad cannot be pressed because it is currently disabled. Please check Pad::enabled before calling Pad::press.");
}
else
{
@ -304,8 +314,8 @@ namespace sb
}
/*!
* By default, a pad object is enabled to accept input presses. If the pad is disabled, however, the press function will not be able to be
* used and will throw an exception. This function can be used both to check the state and to set the state.
* By default, a pad object is enabled to accept input presses. If the pad is disabled, however, the press function will not
* be able to be used and will throw an exception. This function can be used both to check the state and to set the state.
*
* @param state Set to false to disable, true to enable, or omit to check the current state
* @return True if button is set to enabled
@ -320,14 +330,23 @@ namespace sb
}
/*!
* Use this function to prevent the draw function from running, which will prevent the pad object from being rendered. Note that this does
* not disable input. To do that, use Pad::enabled(bool)
* Use this function to prevent the draw function from running, which will prevent the pad object from being rendered. Note
* that this does not disable input. To do that, use Pad::enabled(bool)
*
* @param state Set to false to prevent the pad from being drawn, set to true to re-enable drawing
*/
void visible(bool state = true)
bool visible(bool state)
{
_visible = state;
return _visible;
}
/*!
* @return the pad's visibility state
*/
bool visible() const
{
return _visible;
}
};
}

View File

@ -1,3 +1,13 @@
/* +-------------------------------------------------------+
____/ \____ /| Open source game framework licensed to freely use, |
\ / / | copy, and modify, created for dank.game |
+--\ ^__^ /--+ | |
| ~/ \~ | | Download at https://open.shampoo.ooo/shampoo/spacebox |
| ~~~~~~~~~~~~ | +-------------------------------------------------------+
| SPACE ~~~~~ | /
| ~~~~~~~ BOX |/
+-------------*/
#include "Text.hpp"
using namespace sb;

View File

@ -1,3 +1,13 @@
/* +-------------------------------------------------------+
____/ \____ /| Open source game framework licensed to freely use, |
\ / / | copy, and modify, created for dank.game |
+--\ ^__^ /--+ | |
| ~/ \~ | | Download at https://open.shampoo.ooo/shampoo/spacebox |
| ~~~~~~~~~~~~ | +-------------------------------------------------------+
| SPACE ~~~~~ | /
| ~~~~~~~ BOX |/
+-------------*/
#include <optional>
#include <stdexcept>
@ -30,15 +40,15 @@ namespace sb
public:
/*!
* Construct a sb::Text object from a font, string, and background and foreground colors. A texture will be created and attached at
* texture index 0. The texture is not generated or rendered. Text::refresh() must be called afterward with the GL context loaded to render
* the text to the constructed texture.
* Construct a sb::Text object from a font, string, and background and foreground colors. A texture will be created and attached
* at texture index 0. The texture is not generated or rendered. Text::refresh() must be called afterward with the GL context
* loaded to render the text to the constructed texture.
*
* The font must be wrapped in a shared pointer. A default loaded font is available from Game::font().
*
* Dimensions can be given in pixels, in which case the text will be rendered at the center of a texture in exactly the given dimensions,
* regardless of the length of the text. If the given dimensions are larger than the text, the resulting texture will have padding around
* the text. This can be useful, for example, for creating identically sized text buttons.
* Dimensions can be given in pixels, in which case the text will be rendered at the center of a texture in exactly the given
* dimensions, regardless of the length of the text. If the given dimensions are larger than the text, the resulting texture will
* have padding around the text. This can be useful, for example, for creating identically sized text buttons.
*
* @param font a TTF_Font object wrapped in a shared pointer
* @param content text content

View File

@ -27,6 +27,7 @@
#include <cmath>
#include <fstream>
#include <cstdlib>
#include <initializer_list>
/* SDL shared libraries */
#include "SDL.h"
@ -121,8 +122,9 @@ namespace sb
/*!
* Copy the pixel data in a given rectangular area of an SDL surface into a new SDL surface.
*
* @warning The coordinate system of the rectangular area is expected to be in SDL format, meaning y=0 at the top of the surface, and y=height
* at the bottom. However, the Box class uses GL format by default. To set the Y-axis to SDL format, pass false to Box::invert_y(bool).
* @warning The coordinate system of the rectangular area is expected to be in SDL format, meaning y=0 at the top of the surface, and
* y=height at the bottom. However, the Box class uses GL format by default. To set the Y-axis to SDL format, pass false to
* Box::invert_y(bool).
*
* @param source surface to copy pixels from
* @param area rectangular area to copy
@ -131,13 +133,13 @@ namespace sb
std::shared_ptr<SDL_Surface> extract_area(const std::shared_ptr<SDL_Surface>& surface, const sb::Box& area);
/*!
* Copy pixel data from a given SDL surface into a vector of new SDL surfaces, transforming the original surface into equally sized tiles.
* The number of tiles and size of each tile is determined by the count parameter. Count is a 2D vector indicating how many tiles per row
* and how many rows. For example, if count is {4, 3}, 12 tiles total will be created, 4 per row.
* Copy pixel data from a given SDL surface into a vector of new SDL surfaces, transforming the original surface into equally sized
* tiles. The number of tiles and size of each tile is determined by the count parameter. Count is a 2D vector indicating how many
* tiles per row and how many rows. For example, if count is {4, 3}, 12 tiles total will be created, 4 per row.
*
* The tiles will be in order from the top left tile, going row by row until the bottom right tile. Note that y=0 at the top of image, not
* the bottom, which is common in image manipulation, although is not the coordinate system GL uses, so tile 0 on the Y-axis is the top of
* the image in this function.
* The tiles will be in order from the top left tile, going row by row until the bottom right tile. Note that y=0 at the top of image,
* not the bottom, which is common in image manipulation, although is not the coordinate system GL uses, so tile 0 on the Y-axis is
* the top of the image in this function.
*
* If the count of tiles does not divide evenly into the number of pixels in the surface in either dimension, the rightmost and/or
* bottommost tiles will be smaller than the rest.