Skip to content

Commit

Permalink
Add from_data constructors
Browse files Browse the repository at this point in the history
  • Loading branch information
17cupsofcoffee committed Feb 3, 2019
1 parent d918551 commit bd13b30
Show file tree
Hide file tree
Showing 4 changed files with 88 additions and 34 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,10 @@ This project adheres to Semantic Versioning.

## Upcoming

### Added

* `from_data` constructors were added to `Texture`, `Font` and `Sound`, allowing them to be constructed from binary data. This is useful if you want to use `include_bytes` to bundle assets into your executable. Note that an equivalent constructor already existed on `Shader`, which can be used in combination with `include_str`.

### Changed

* The default shaders have been amended to use GLSL 1.50 instead of GLSL 1.30. This seems to be required to get Tetra working on Mac.
Expand Down
66 changes: 39 additions & 27 deletions src/audio.rs
Original file line number Diff line number Diff line change
Expand Up @@ -52,9 +52,9 @@ pub struct Sound {

impl Sound {
/// Creates a new sound from the given file.
///
///
/// # Errors
///
///
/// If the file path is invalid, a `TetraError::Io` will be returned. Note that the data
/// is not decoded until playback begins, so this function will not validate
/// that the data being read is formatted correctly.
Expand All @@ -67,67 +67,78 @@ impl Sound {
})
}

/// Plays the sound.
/// Creates a new sound from a slice of binary data.
///
/// # Errors
/// This is useful in combination with `include_bytes`, as it allows you to include
/// your audio data directly in the binary.
///
/// Note that the data is not decoded until playback begins, so this function will not
/// validate that the data being read is formatted correctly.
pub fn from_data(data: &[u8]) -> Sound {
Sound { data: data.into() }
}

/// Plays the sound.
///
/// # Errors
///
/// If there is no active audio device, a `TetraError::NoAudioDevice` will be returned.
///
///
/// If the sound data could not be decoded, a `TetraError::FailedToDecodeAudio` will be returned.
pub fn play(&self, ctx: &Context) -> Result<SoundInstance> {
self.start_source(ctx, true, false, 1.0, 1.0)
}

/// Plays the sound repeatedly.
///
///
/// # Errors
///
///
/// If there is no active audio device, a `TetraError::NoAudioDevice` will be returned.
///
///
/// If the sound data could not be decoded, a `TetraError::FailedToDecodeAudio` will be returned.
pub fn repeat(&self, ctx: &Context) -> Result<SoundInstance> {
self.start_source(ctx, true, true, 1.0, 1.0)
}

/// Spawns a new instance of the sound that is not playing yet.
///
///
/// # Errors
///
///
/// If there is no active audio device, a `TetraError::NoAudioDevice` will be returned.
///
///
/// If the sound data could not be decoded, a `TetraError::FailedToDecodeAudio` will be returned.
pub fn spawn(&self, ctx: &Context) -> Result<SoundInstance> {
self.start_source(ctx, false, false, 1.0, 1.0)
}

/// Plays the sound, with the provided settings.
///
///
/// # Errors
///
///
/// If there is no active audio device, a `TetraError::NoAudioDevice` will be returned.
///
///
/// If the sound data could not be decoded, a `TetraError::FailedToDecodeAudio` will be returned.
pub fn play_with(&self, ctx: &Context, volume: f32, speed: f32) -> Result<SoundInstance> {
self.start_source(ctx, true, false, volume, speed)
}

/// Plays the sound repeatedly, with the provided settings.
///
///
/// # Errors
///
///
/// If there is no active audio device, a `TetraError::NoAudioDevice` will be returned.
///
///
/// If the sound data could not be decoded, a `TetraError::FailedToDecodeAudio` will be returned.
pub fn repeat_with(&self, ctx: &Context, volume: f32, speed: f32) -> Result<SoundInstance> {
self.start_source(ctx, true, true, volume, speed)
}

/// Spawns a new instance of the sound that is not playing yet, with the provided settings.
///
///
/// # Errors
///
///
/// If there is no active audio device, a `TetraError::NoAudioDevice` will be returned.
///
///
/// If the sound data could not be decoded, a `TetraError::FailedToDecodeAudio` will be returned.
pub fn spawn_with(&self, ctx: &Context, volume: f32, speed: f32) -> Result<SoundInstance> {
self.start_source(ctx, false, false, volume, speed)
Expand All @@ -149,9 +160,7 @@ impl Sound {
speed: Mutex::new(speed),
});

let master_volume = {
*ctx.audio.master_volume.lock().unwrap()
};
let master_volume = { *ctx.audio.master_volume.lock().unwrap() };

let source = TetraSource {
data: Arc::clone(&self.data),
Expand All @@ -170,7 +179,10 @@ impl Sound {
speed,
};

rodio::play_raw(ctx.audio.device.as_ref().ok_or(TetraError::NoAudioDevice)?, source.convert_samples());
rodio::play_raw(
ctx.audio.device.as_ref().ok_or(TetraError::NoAudioDevice)?,
source.convert_samples(),
);
Ok(SoundInstance { controls })
}
}
Expand All @@ -185,7 +197,7 @@ struct RemoteControls {
}

/// A handle to a single instance of a [`Sound`](./struct.Sound.html).
///
///
/// The audio thread will poll this for updates every 220 samples (roughly
/// every 5ms at a 44100hz sample rate).
///
Expand Down Expand Up @@ -359,7 +371,7 @@ impl Source for TetraSource {
}

/// Sets the master volume for the game.
///
///
/// The parameter is used as a multiplier - for example, `1.0` would result in
/// sounds being played back at their original volume.
pub fn set_master_volume(ctx: &mut Context, volume: f32) {
Expand All @@ -369,4 +381,4 @@ pub fn set_master_volume(ctx: &mut Context, volume: f32) {
/// Gets the master volume for the game.
pub fn get_master_volume(ctx: &mut Context) -> f32 {
*ctx.audio.master_volume.lock().unwrap()
}
}
14 changes: 14 additions & 0 deletions src/graphics/text.rs
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,20 @@ impl Font {

Ok(Font { id })
}

/// Loads a font from a slice of binary data.
///
/// This is useful in combination with `include_bytes`, as it allows you to
/// include your fonts directly in the binary.
///
/// Note that this function currently requires the slice to have the `'static`
/// lifetime due to the way that the font cache is implemented - this may change
/// in the future.
pub fn from_data(ctx: &mut Context, data: &'static [u8]) -> Font {
let id = ctx.graphics.font_cache.add_font_bytes(data);

Font { id }
}
}

impl Default for Font {
Expand Down
38 changes: 31 additions & 7 deletions src/graphics/texture.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
use std::path::Path;
use std::rc::Rc;

use image;
use image::{self, DynamicImage};

use crate::error::Result;
use crate::graphics::opengl::{GLTexture, TextureFormat};
Expand All @@ -21,26 +21,50 @@ pub struct Texture {

impl Texture {
/// Creates a new texture from the given file.
///
///
/// The format will be determined based on the file extension.
///
/// # Errors
///
///
/// If the file could not be read, a `TetraError::Io` will be returned.
///
///
/// If the image data was invalid, a `TetraError::Image` will be returned.
pub fn new<P>(ctx: &mut Context, path: P) -> Result<Texture>
where
P: AsRef<Path>,
{
let image = image::open(path)?.to_rgba();
let (width, height) = image.dimensions();
let image = image::open(path)?;
Texture::load(ctx, image)
}

/// Creates a new texture from a slice of binary data.
///
/// This is useful in combination with `include_bytes`, as it allows you to include
/// your textures directly in the binary.
///
/// The format will be determined based on the 'magic bytes' at the beginning of the
/// data. This should be reasonably reliable, but a `from_data_with_format` function
/// might have to be added later.
///
/// # Errors
///
/// If the image data was invalid, a `TetraError::Image` will be returned.
pub fn from_data(ctx: &mut Context, data: &[u8]) -> Result<Texture> {
let image = image::load_from_memory(data)?;
Texture::load(ctx, image)
}

pub(crate) fn load(ctx: &mut Context, image: DynamicImage) -> Result<Texture> {
let rgba_image = image.to_rgba();
let (width, height) = rgba_image.dimensions();

let texture = ctx
.gl
.new_texture(width as i32, height as i32, TextureFormat::Rgba);

ctx.gl.set_texture_data(
&texture,
&image,
&rgba_image,
0,
0,
width as i32,
Expand Down

0 comments on commit bd13b30

Please sign in to comment.