From 9e8232d7503e686f49e55eb388c0e8670e247277 Mon Sep 17 00:00:00 2001 From: raysan5 Date: Mon, 25 Jul 2016 19:44:21 +0200 Subject: Redesigned bloom shader to work on RPI --- examples/resources/shaders/glsl100/bloom.fs | 30 +++++++++++++++-------------- examples/resources/shaders/glsl330/bloom.fs | 30 +++++++++++++++-------------- 2 files changed, 32 insertions(+), 28 deletions(-) (limited to 'examples/resources') diff --git a/examples/resources/shaders/glsl100/bloom.fs b/examples/resources/shaders/glsl100/bloom.fs index 128736f2..a8e1d20f 100644 --- a/examples/resources/shaders/glsl100/bloom.fs +++ b/examples/resources/shaders/glsl100/bloom.fs @@ -8,30 +8,32 @@ varying vec4 fragColor; // Input uniform values uniform sampler2D texture0; -uniform vec4 fragTintColor; +uniform vec4 colDiffuse; // NOTE: Add here your custom variables +const vec2 size = vec2(800, 450); // render size +const float samples = 5.0; // pixels per axis; higher = bigger glow, worse performance +const float quality = 2.5; // lower = smaller glow, better quality + void main() { vec4 sum = vec4(0); - vec4 tc = vec4(0); + vec2 sizeFactor = vec2(1)/size*quality; + + // Texel color fetching from texture sampler + vec4 source = texture2D(texture0, fragTexCoord); - for (int i = -4; i < 4; i++) + const int range = 2; // should be = (samples - 1)/2; + + for (int x = -range; x <= range; x++) { - for (int j = -3; j < 3; j++) + for (int y = -range; y <= range; y++) { - sum += texture2D(texture0, fragTexCoord + vec2(j, i)*0.004) * 0.25; + sum += texture2D(texture0, fragTexCoord + vec2(x, y)*sizeFactor); } } - - // Texel color fetching from texture sampler - vec4 texelColor = texture2D(texture0, fragTexCoord); - + // Calculate final fragment color - if (texelColor.r < 0.3) tc = sum*sum*0.012 + texelColor; - else if (texelColor.r < 0.5) tc = sum*sum*0.009 + texelColor; - else tc = sum*sum*0.0075 + texelColor; - - gl_FragColor = tc; + gl_FragColor = ((sum/(samples*samples)) + source)*colDiffuse; } \ No newline at end of file diff --git a/examples/resources/shaders/glsl330/bloom.fs b/examples/resources/shaders/glsl330/bloom.fs index 0307bc06..333d5b05 100644 --- a/examples/resources/shaders/glsl330/bloom.fs +++ b/examples/resources/shaders/glsl330/bloom.fs @@ -6,33 +6,35 @@ in vec4 fragColor; // Input uniform values uniform sampler2D texture0; -uniform vec4 fragTintColor; +uniform vec4 colDiffuse; // Output fragment color out vec4 finalColor; // NOTE: Add here your custom variables +const vec2 size = vec2(800, 450); // render size +const float samples = 5.0; // pixels per axis; higher = bigger glow, worse performance +const float quality = 2.5; // lower = smaller glow, better quality + void main() { vec4 sum = vec4(0); - vec4 tc = vec4(0); + vec2 sizeFactor = vec2(1)/size*quality; + + // Texel color fetching from texture sampler + vec4 source = texture(texture0, fragTexCoord); + + const int range = 2; // should be = (samples - 1)/2; - for (int i = -4; i < 4; i++) + for (int x = -range; x <= range; x++) { - for (int j = -3; j < 3; j++) + for (int y = -range; y <= range; y++) { - sum += texture(texture0, fragTexCoord + vec2(j, i)*0.004)*0.25; + sum += texture(texture0, fragTexCoord + vec2(x, y)*sizeFactor); } } - - // Texel color fetching from texture sampler - vec4 texelColor = texture(texture0, fragTexCoord); - - // Calculate final fragment color - if (texelColor.r < 0.3) tc = sum*sum*0.012 + texelColor; - else if (texelColor.r < 0.5) tc = sum*sum*0.009 + texelColor; - else tc = sum*sum*0.0075 + texelColor; - finalColor = tc; + // Calculate final fragment color + finalColor = ((sum/(samples*samples)) + source)*colDiffuse; } \ No newline at end of file -- cgit v1.2.3 From 68d647c1af1b9f0479f680dbd7c4f93586cd51a2 Mon Sep 17 00:00:00 2001 From: raysan5 Date: Tue, 2 Aug 2016 17:32:24 +0200 Subject: Complete review and update Simplified module for Music and AudioStream Added support for raw audio streaming (with example) --- examples/audio_module_playing.c | 2 +- examples/audio_music_stream.c | 3 - examples/audio_raw_stream.c | 106 ++++++++++++++++ examples/audio_sound_loading.c | 1 - examples/resources/audio/2t2m_spa.xm | Bin 2287400 -> 0 bytes examples/resources/audio/chiptun1.mod | Bin 0 -> 2142 bytes examples/resources/audio/mini1111.xm | Bin 0 -> 25676 bytes src/audio.c | 230 ++++++++++++++++++---------------- src/audio.h | 27 +++- src/raylib.h | 29 ++++- 10 files changed, 277 insertions(+), 121 deletions(-) create mode 100644 examples/audio_raw_stream.c delete mode 100644 examples/resources/audio/2t2m_spa.xm create mode 100644 examples/resources/audio/chiptun1.mod create mode 100644 examples/resources/audio/mini1111.xm (limited to 'examples/resources') diff --git a/examples/audio_module_playing.c b/examples/audio_module_playing.c index 07165c76..fe9ea15c 100644 --- a/examples/audio_module_playing.c +++ b/examples/audio_module_playing.c @@ -57,7 +57,7 @@ int main() // Create a RenderTexture2D to be used for render to texture RenderTexture2D target = LoadRenderTexture(screenWidth, screenHeight); - Music xm = LoadMusicStream("resources/audio/2t2m_spa.xm"); + Music xm = LoadMusicStream("resources/audio/mini1111.xm"); PlayMusicStream(xm); diff --git a/examples/audio_music_stream.c b/examples/audio_music_stream.c index 1d86bd1a..c552d030 100644 --- a/examples/audio_music_stream.c +++ b/examples/audio_music_stream.c @@ -59,9 +59,6 @@ int main() SetMusicVolume(volume); } */ - if (IsWindowMinimized()) PauseMusicStream(music); - else ResumeMusicStream(music); - timePlayed = GetMusicTimePlayed(music)/GetMusicTimeLength(music)*100*4; // We scale by 4 to fit 400 pixels UpdateMusicStream(music); // Update music buffer with new stream data diff --git a/examples/audio_raw_stream.c b/examples/audio_raw_stream.c new file mode 100644 index 00000000..37a5b4ff --- /dev/null +++ b/examples/audio_raw_stream.c @@ -0,0 +1,106 @@ +/******************************************************************************************* +* +* raylib [audio] example - Raw audio streaming +* +* NOTE: This example requires OpenAL Soft library installed +* +* This example has been created using raylib 1.6 (www.raylib.com) +* raylib is licensed under an unmodified zlib/libpng license (View raylib.h for details) +* +* Copyright (c) 2015 Ramon Santamaria (@raysan5) +* +********************************************************************************************/ + +#include "raylib.h" + +#include // Required for: malloc(), free() +#include // Required for: sinf() + +int main() +{ + // Initialization + //-------------------------------------------------------------------------------------- + int screenWidth = 800; + int screenHeight = 450; + + SetConfigFlags(FLAG_MSAA_4X_HINT); + InitWindow(screenWidth, screenHeight, "raylib [audio] example - raw audio streaming"); + + InitAudioDevice(); // Initialize audio device + + AudioStream stream = InitAudioStream(44100, 32, 1); // Init raw audio stream + + // Fill audio stream with some samples (sine wave) + float *data = (float *)malloc(sizeof(float)*44100); + + for (int i = 0; i < 44100; i++) + { + data[i] = sinf(2*PI*(float)i*DEG2RAD); + } + + PlayAudioStream(stream); + + int totalSamples = 44100; + int samplesLeft = totalSamples; + + Vector2 position = { 0, 0 }; + + SetTargetFPS(30); // Set our game to run at 30 frames-per-second + //-------------------------------------------------------------------------------------- + + // Main game loop + while (!WindowShouldClose()) // Detect window close button or ESC key + { + // Update + //---------------------------------------------------------------------------------- + + // Refill audio stream if required + if (IsAudioBufferProcessed(stream)) + { + int numSamples = 0; + if (samplesLeft >= 4096) numSamples = 4096; + else numSamples = samplesLeft; + + UpdateAudioStream(stream, data + (totalSamples - samplesLeft), numSamples); + + samplesLeft -= numSamples; + + // Reset samples feeding (loop audio) + if (samplesLeft <= 0) samplesLeft = totalSamples; + } + //---------------------------------------------------------------------------------- + + // Draw + //---------------------------------------------------------------------------------- + BeginDrawing(); + + ClearBackground(RAYWHITE); + + DrawText("SINE WAVE SHOULD BE PLAYING!", 240, 140, 20, LIGHTGRAY); + + // NOTE: Draw a part of the sine wave (only screen width) + for (int i = 0; i < GetScreenWidth(); i++) + { + position.x = i; + position.y = 250 + 50*data[i]; + + DrawPixelV(position, RED); + } + + EndDrawing(); + //---------------------------------------------------------------------------------- + } + + // De-Initialization + //-------------------------------------------------------------------------------------- + free(data); // Unload sine wave data + + CloseAudioStream(stream); // Close raw audio stream and delete buffers from RAM + + CloseAudioDevice(); // Close audio device (music streaming is automatically stopped) + + CloseWindow(); // Close window and OpenGL context + //-------------------------------------------------------------------------------------- + + return 0; +} \ No newline at end of file diff --git a/examples/audio_sound_loading.c b/examples/audio_sound_loading.c index 8819aad1..f081e8ed 100644 --- a/examples/audio_sound_loading.c +++ b/examples/audio_sound_loading.c @@ -36,7 +36,6 @@ int main() // Update //---------------------------------------------------------------------------------- if (IsKeyPressed(KEY_SPACE)) PlaySound(fxWav); // Play WAV sound - if (IsKeyPressed(KEY_ENTER)) PlaySound(fxOgg); // Play OGG sound //---------------------------------------------------------------------------------- diff --git a/examples/resources/audio/2t2m_spa.xm b/examples/resources/audio/2t2m_spa.xm deleted file mode 100644 index fa416ef2..00000000 Binary files a/examples/resources/audio/2t2m_spa.xm and /dev/null differ diff --git a/examples/resources/audio/chiptun1.mod b/examples/resources/audio/chiptun1.mod new file mode 100644 index 00000000..00d16885 Binary files /dev/null and b/examples/resources/audio/chiptun1.mod differ diff --git a/examples/resources/audio/mini1111.xm b/examples/resources/audio/mini1111.xm new file mode 100644 index 00000000..a185c1a2 Binary files /dev/null and b/examples/resources/audio/mini1111.xm differ diff --git a/src/audio.c b/src/audio.c index d1c425d5..befed61c 100644 --- a/src/audio.c +++ b/src/audio.c @@ -100,17 +100,6 @@ typedef enum { MUSIC_AUDIO_OGG = 0, MUSIC_MODULE_XM, MUSIC_MODULE_MOD } MusicContextType; -// Used to create custom audio streams that are not bound to a specific file. -typedef struct AudioStream { - unsigned int sampleRate; // Frequency (samples per second): default is 48000 - unsigned int sampleSize; // BitDepth (bits per sample): 8, 16, 32 (24 not supported) - unsigned int channels; // Number of channels - - ALenum format; // OpenAL format specifier - ALuint source; // OpenAL source - ALuint buffers[MAX_STREAM_BUFFERS]; // OpenAL buffers (double buffering) -} AudioStream; - // Music type (file streaming from memory) typedef struct Music { MusicContextType ctxType; // Type of music context (OGG, XM, MOD) @@ -118,7 +107,7 @@ typedef struct Music { jar_xm_context_t *ctxXm; // XM chiptune context jar_mod_context_t ctxMod; // MOD chiptune context - AudioStream stream; // Audio stream + AudioStream stream; // Audio stream (double buffering) bool loop; // Repeat music after finish (loop) unsigned int totalSamples; // Total number of samples @@ -141,12 +130,6 @@ static Wave LoadWAV(const char *fileName); // Load WAV file static Wave LoadOGG(char *fileName); // Load OGG file static void UnloadWave(Wave wave); // Unload wave data -static bool BufferMusicStream(Music music, int numBuffersToProcess); // Fill music buffers with data - -static AudioStream InitAudioStream(unsigned int sampleRate, unsigned int sampleSize, unsigned int channels); -static void BufferAudioStream(AudioStream stream, void *data, int numSamples); -static void CloseAudioStream(AudioStream stream); - #if defined(AUDIO_STANDALONE) const char *GetExtension(const char *fileName); // Get the extension for a filename void TraceLog(int msgType, const char *text, ...); // Outputs a trace log message (INFO, ERROR, WARNING) @@ -595,33 +578,89 @@ void StopMusicStream(Music music) // Update (re-fill) music buffers if data already processed void UpdateMusicStream(Music music) { - ALenum state; - bool active = true; ALint processed = 0; // Determine if music stream is ready to be written alGetSourcei(music->stream.source, AL_BUFFERS_PROCESSED, &processed); - + + int numBuffersToProcess = processed; + if (processed > 0) { - active = BufferMusicStream(music, processed); + bool active = true; + short pcm[AUDIO_BUFFER_SIZE]; + float pcmf[AUDIO_BUFFER_SIZE]; + + int numSamples = 0; // Total size of data steamed in L+R samples for xm floats, + // individual L or R for ogg shorts + + for (int i = 0; i < numBuffersToProcess; i++) + { + switch (music->ctxType) + { + case MUSIC_AUDIO_OGG: + { + if (music->samplesLeft >= AUDIO_BUFFER_SIZE) numSamples = AUDIO_BUFFER_SIZE; + else numSamples = music->samplesLeft; + + // NOTE: Returns the number of samples to process (should be the same as numSamples -> it is) + int numSamplesOgg = stb_vorbis_get_samples_short_interleaved(music->ctxOgg, music->stream.channels, pcm, numSamples); + + // TODO: Review stereo channels Ogg, not enough samples served! + UpdateAudioStream(music->stream, pcm, numSamples*music->stream.channels); + music->samplesLeft -= (numSamples*music->stream.channels); + + } break; + case MUSIC_MODULE_XM: + { + if (music->samplesLeft >= AUDIO_BUFFER_SIZE/2) numSamples = AUDIO_BUFFER_SIZE/2; + else numSamples = music->samplesLeft; + + // NOTE: Output buffer is 2*numsamples elements (left and right value for each sample) + jar_xm_generate_samples(music->ctxXm, pcmf, numSamples); + UpdateAudioStream(music->stream, pcmf, numSamples*2); // Using 32bit PCM data + music->samplesLeft -= numSamples; + + //TraceLog(INFO, "Samples left: %i", music->samplesLeft); + + } break; + case MUSIC_MODULE_MOD: + { + if (music->samplesLeft >= AUDIO_BUFFER_SIZE/2) numSamples = AUDIO_BUFFER_SIZE/2; + else numSamples = music->samplesLeft; + + // NOTE: Output buffer size is nbsample*channels (default: 48000Hz, 16bit, Stereo) + jar_mod_fillbuffer(&music->ctxMod, pcm, numSamples, 0); + UpdateAudioStream(music->stream, pcm, numSamples*2); + music->samplesLeft -= numSamples; + + } break; + default: break; + } + if (music->samplesLeft <= 0) + { + active = false; + break; + } + } + + // Reset audio stream for looping if (!active && music->loop) { // Restart music context (if required) + //if (music->ctxType == MUSIC_MODULE_XM) if (music->ctxType == MUSIC_MODULE_MOD) jar_mod_seek_start(&music->ctxMod); else if (music->ctxType == MUSIC_AUDIO_OGG) stb_vorbis_seek_start(music->ctxOgg); + // Reset samples left to total samples music->samplesLeft = music->totalSamples; - - // Determine if music stream is ready to be written - alGetSourcei(music->stream.source, AL_BUFFERS_PROCESSED, &processed); - - active = BufferMusicStream(music, processed); } - if (alGetError() != AL_NO_ERROR) TraceLog(WARNING, "Error buffering data..."); + // This error is registered when UpdateAudioStream() fails + if (alGetError() == AL_INVALID_VALUE) TraceLog(WARNING, "OpenAL: Error buffering data..."); + ALenum state; alGetSourcei(music->stream.source, AL_SOURCE_STATE, &state); if (state != AL_PLAYING && active) alSourcePlay(music->stream.source); @@ -668,36 +707,14 @@ float GetMusicTimePlayed(Music music) { float secondsPlayed = 0.0f; - if (music->ctxType == MUSIC_MODULE_XM) - { - uint64_t samplesPlayed; - jar_xm_get_position(music->ctxXm, NULL, NULL, NULL, &samplesPlayed); - - // TODO: Not sure if this is the correct value - secondsPlayed = (float)samplesPlayed/(music->stream.sampleRate*music->stream.channels); - } - else if (music->ctxType == MUSIC_MODULE_MOD) - { - long samplesPlayed = jar_mod_current_samples(&music->ctxMod); - - secondsPlayed = (float)samplesPlayed/music->stream.sampleRate; - } - else if (music->ctxType == MUSIC_AUDIO_OGG) - { - unsigned int samplesPlayed = music->totalSamples - music->samplesLeft; - - secondsPlayed = (float)samplesPlayed/(music->stream.sampleRate*music->stream.channels); - } + unsigned int samplesPlayed = music->totalSamples - music->samplesLeft; + secondsPlayed = (float)samplesPlayed/(music->stream.sampleRate*music->stream.channels); return secondsPlayed; } -//---------------------------------------------------------------------------------- -// Module specific Functions Definition -//---------------------------------------------------------------------------------- - // Init audio stream (to stream audio pcm data) -static AudioStream InitAudioStream(unsigned int sampleRate, unsigned int sampleSize, unsigned int channels) +AudioStream InitAudioStream(unsigned int sampleRate, unsigned int sampleSize, unsigned int channels) { AudioStream stream = { 0 }; @@ -735,7 +752,7 @@ static AudioStream InitAudioStream(unsigned int sampleRate, unsigned int sampleS alSource3f(stream.source, AL_POSITION, 0, 0, 0); alSource3f(stream.source, AL_VELOCITY, 0, 0, 0); - // Create Buffers + // Create Buffers (double buffering) alGenBuffers(MAX_STREAM_BUFFERS, stream.buffers); // Initialize buffer with zeros by default @@ -766,7 +783,7 @@ static AudioStream InitAudioStream(unsigned int sampleRate, unsigned int sampleS } // Close audio stream and free memory -static void CloseAudioStream(AudioStream stream) +void CloseAudioStream(AudioStream stream) { // Stop playing channel alSourceStop(stream.source); @@ -790,75 +807,66 @@ static void CloseAudioStream(AudioStream stream) TraceLog(INFO, "[AUD ID %i] Unloaded audio stream data", stream.source); } -// Push more audio data into audio stream, only one buffer per call -static void BufferAudioStream(AudioStream stream, void *data, int numSamples) -{ +// Update audio stream buffers with data +// NOTE: Only one buffer per call +void UpdateAudioStream(AudioStream stream, void *data, int numSamples) +{ ALuint buffer = 0; alSourceUnqueueBuffers(stream.source, 1, &buffer); - //TraceLog(DEBUG, "Buffer to refill: %i", buffer); + // Check if any buffer was available for unqueue + if (alGetError() != AL_INVALID_VALUE) + { + if (stream.sampleSize == 8) alBufferData(buffer, stream.format, (unsigned char *)data, numSamples*sizeof(unsigned char), stream.sampleRate); + else if (stream.sampleSize == 16) alBufferData(buffer, stream.format, (short *)data, numSamples*sizeof(short), stream.sampleRate); + else if (stream.sampleSize == 32) alBufferData(buffer, stream.format, (float *)data, numSamples*sizeof(float), stream.sampleRate); + + alSourceQueueBuffers(stream.source, 1, &buffer); + } +} + +// Check if any audio stream buffers requires refill +bool IsAudioBufferProcessed(AudioStream stream) +{ + ALint processed = 0; - if (stream.sampleSize == 8) alBufferData(buffer, stream.format, (unsigned char *)data, numSamples*sizeof(unsigned char), stream.sampleRate); - else if (stream.sampleSize == 16) alBufferData(buffer, stream.format, (short *)data, numSamples*sizeof(short), stream.sampleRate); - else if (stream.sampleSize == 32) alBufferData(buffer, stream.format, (float *)data, numSamples*sizeof(float), stream.sampleRate); + // Determine if music stream is ready to be written + alGetSourcei(stream.source, AL_BUFFERS_PROCESSED, &processed); - alSourceQueueBuffers(stream.source, 1, &buffer); + return (processed > 0); } -// Fill music buffers with new data from music stream -static bool BufferMusicStream(Music music, int numBuffersToProcess) +// Play audio stream +void PlayAudioStream(AudioStream stream) { - short pcm[AUDIO_BUFFER_SIZE]; - float pcmf[AUDIO_BUFFER_SIZE]; + alSourcePlay(stream.source); +} - int size = 0; // Total size of data steamed in L+R samples for xm floats, individual L or R for ogg shorts - bool active = true; // We can get more data from stream (not finished) - - for (int i = 0; i < numBuffersToProcess; i++) - { - if (music->samplesLeft >= AUDIO_BUFFER_SIZE) size = AUDIO_BUFFER_SIZE; - else size = music->samplesLeft; +// Play audio stream +void PauseAudioStream(AudioStream stream) +{ + alSourcePause(stream.source); +} - switch (music->ctxType) - { - case MUSIC_AUDIO_OGG: - { - // NOTE: Returns the number of samples to process (should be the same as size) - int numSamples = stb_vorbis_get_samples_short_interleaved(music->ctxOgg, music->stream.channels, pcm, size); - - BufferAudioStream(music->stream, pcm, numSamples*music->stream.channels); - music->samplesLeft -= (numSamples*music->stream.channels); - - } break; - case MUSIC_MODULE_XM: - { - // NOTE: Output buffer is 2*numsamples elements (left and right value for each sample) - jar_xm_generate_samples(music->ctxXm, pcmf, size/2); - BufferAudioStream(music->stream, pcmf, size); // Using 32bit PCM data - music->samplesLeft -= (size/2); - - } break; - case MUSIC_MODULE_MOD: - { - // NOTE: Output buffer size is nbsample*channels (default: 48000Hz, 16bit, Stereo) - jar_mod_fillbuffer(&music->ctxMod, pcm, size/2, 0); - BufferAudioStream(music->stream, pcm, size); - music->samplesLeft -= (size/2); - - } break; - default: break; - } +// Resume audio stream playing +void ResumeAudioStream(AudioStream stream) +{ + ALenum state; + alGetSourcei(stream.source, AL_SOURCE_STATE, &state); - if (music->samplesLeft <= 0) - { - active = false; - break; - } - } - - return active; + if (state == AL_PAUSED) alSourcePlay(stream.source); } +// Stop audio stream +void StopAudioStream(AudioStream stream) +{ + alSourceStop(stream.source); +} + +//---------------------------------------------------------------------------------- +// Module specific Functions Definition +//---------------------------------------------------------------------------------- + // Load WAV file into Wave structure static Wave LoadWAV(const char *fileName) { diff --git a/src/audio.h b/src/audio.h index c9171339..dbd88939 100644 --- a/src/audio.h +++ b/src/audio.h @@ -76,9 +76,21 @@ typedef struct Wave { } Wave; // Music type (file streaming from memory) -// NOTE: Anything longer than ~10 seconds should be streamed into a mix channel... +// NOTE: Anything longer than ~10 seconds should be streamed typedef struct Music *Music; +// Audio stream type +// NOTE: Useful to create custom audio streams not bound to a specific file +typedef struct AudioStream { + unsigned int sampleRate; // Frequency (samples per second) + unsigned int sampleSize; // Bit depth (bits per sample): 8, 16, 32 (24 not supported) + unsigned int channels; // Number of channels (1-mono, 2-stereo) + + int format; // OpenAL audio format specifier + unsigned int source; // OpenAL audio source id + unsigned int buffers[2]; // OpenAL audio buffers (double buffering) +} AudioStream; + #ifdef __cplusplus extern "C" { // Prevents name mangling of functions #endif @@ -93,7 +105,7 @@ extern "C" { // Prevents name mangling of functions //---------------------------------------------------------------------------------- void InitAudioDevice(void); // Initialize audio device and context void CloseAudioDevice(void); // Close the audio device and context (and music stream) -bool IsAudioDeviceReady(void); // Check if device has been initialized successfully +bool IsAudioDeviceReady(void); // Check if audio device has been initialized successfully Sound LoadSound(char *fileName); // Load sound to memory Sound LoadSoundFromWave(Wave wave); // Load sound to memory from wave data @@ -120,6 +132,17 @@ void SetMusicPitch(Music music, float pitch); // Set pitch for float GetMusicTimeLength(Music music); // Get music time length (in seconds) float GetMusicTimePlayed(Music music); // Get current music time played (in seconds) +AudioStream InitAudioStream(unsigned int sampleRate, + unsigned int sampleSize, + unsigned int channels); // Init audio stream (to stream audio pcm data) +void UpdateAudioStream(AudioStream stream, void *data, int numSamples); // Update audio stream buffers with data +void CloseAudioStream(AudioStream stream); // Close audio stream and free memory +bool IsAudioBufferProcessed(AudioStream stream); // Check if any audio stream buffers requires refill +void PlayAudioStream(AudioStream stream); // Play audio stream +void PauseAudioStream(AudioStream stream); // Pause audio stream +void ResumeAudioStream(AudioStream stream); // Resume audio stream +void StopAudioStream(AudioStream stream); // Stop audio stream + #ifdef __cplusplus } #endif diff --git a/src/raylib.h b/src/raylib.h index 4b9f6ca0..3ee7a793 100644 --- a/src/raylib.h +++ b/src/raylib.h @@ -499,8 +499,8 @@ typedef struct Ray { // Sound source type typedef struct Sound { - unsigned int source; // Sound audio source id - unsigned int buffer; // Sound audio buffer id + unsigned int source; // OpenAL audio source id + unsigned int buffer; // OpenAL audio buffer id } Sound; // Wave type, defines audio wave data @@ -516,6 +516,18 @@ typedef struct Wave { // NOTE: Anything longer than ~10 seconds should be streamed typedef struct Music *Music; +// Audio stream type +// NOTE: Useful to create custom audio streams not bound to a specific file +typedef struct AudioStream { + unsigned int sampleRate; // Frequency (samples per second) + unsigned int sampleSize; // Bit depth (bits per sample): 8, 16, 32 (24 not supported) + unsigned int channels; // Number of channels (1-mono, 2-stereo) + + int format; // OpenAL audio format specifier + unsigned int source; // OpenAL audio source id + unsigned int buffers[2]; // OpenAL audio buffers (double buffering) +} AudioStream; + // Texture formats // NOTE: Support depends on OpenGL version and platform typedef enum { @@ -923,7 +935,7 @@ void ToggleVrMode(void); // Enable/Disable VR experience (dev //------------------------------------------------------------------------------------ void InitAudioDevice(void); // Initialize audio device and context void CloseAudioDevice(void); // Close the audio device and context (and music stream) -bool IsAudioDeviceReady(void); // True if call to InitAudioDevice() was successful and CloseAudioDevice() has not been called yet +bool IsAudioDeviceReady(void); // Check if audio device has been initialized successfully Sound LoadSound(char *fileName); // Load sound to memory Sound LoadSoundFromWave(Wave wave); // Load sound to memory from wave data @@ -950,6 +962,17 @@ void SetMusicPitch(Music music, float pitch); // Set pitch for float GetMusicTimeLength(Music music); // Get music time length (in seconds) float GetMusicTimePlayed(Music music); // Get current music time played (in seconds) +AudioStream InitAudioStream(unsigned int sampleRate, + unsigned int sampleSize, + unsigned int channels); // Init audio stream (to stream audio pcm data) +void UpdateAudioStream(AudioStream stream, void *data, int numSamples); // Update audio stream buffers with data +void CloseAudioStream(AudioStream stream); // Close audio stream and free memory +bool IsAudioBufferProcessed(AudioStream stream); // Check if any audio stream buffers requires refill +void PlayAudioStream(AudioStream stream); // Play audio stream +void PauseAudioStream(AudioStream stream); // Pause audio stream +void ResumeAudioStream(AudioStream stream); // Resume audio stream +void StopAudioStream(AudioStream stream); // Stop audio stream + #ifdef __cplusplus } #endif -- cgit v1.2.3 From 478d3cbb79caa27351cf9e9a5ff9925ca658a89c Mon Sep 17 00:00:00 2001 From: raysan5 Date: Wed, 21 Sep 2016 12:28:49 +0200 Subject: Added standard shader for testing --- examples/resources/shaders/glsl100/standard.fs | 161 +++++++++++++++++++++++++ examples/resources/shaders/glsl100/standard.vs | 23 ++++ examples/resources/shaders/glsl330/standard.fs | 150 +++++++++++++++++++++++ examples/resources/shaders/glsl330/standard.vs | 23 ++++ 4 files changed, 357 insertions(+) create mode 100644 examples/resources/shaders/glsl100/standard.fs create mode 100644 examples/resources/shaders/glsl100/standard.vs create mode 100644 examples/resources/shaders/glsl330/standard.fs create mode 100644 examples/resources/shaders/glsl330/standard.vs (limited to 'examples/resources') diff --git a/examples/resources/shaders/glsl100/standard.fs b/examples/resources/shaders/glsl100/standard.fs new file mode 100644 index 00000000..6ce2a186 --- /dev/null +++ b/examples/resources/shaders/glsl100/standard.fs @@ -0,0 +1,161 @@ +#version 100 + +precision mediump float; + +varying vec3 fragPosition; +varying vec2 fragTexCoord; +varying vec4 fragColor; +varying vec3 fragNormal; + +uniform sampler2D texture0; +uniform sampler2D texture1; +uniform sampler2D texture2; + +uniform vec4 colAmbient; +uniform vec4 colDiffuse; +uniform vec4 colSpecular; +uniform float glossiness; + +uniform int useNormal; +uniform int useSpecular; + +uniform mat4 modelMatrix; +uniform vec3 viewDir; + +struct Light { + int enabled; + int type; + vec3 position; + vec3 direction; + vec4 diffuse; + float intensity; + float radius; + float coneAngle; +}; + +const int maxLights = 8; +uniform Light lights[maxLights]; + +vec3 ComputeLightPoint(Light l, vec3 n, vec3 v, float s) +{ +/* + vec3 surfacePos = vec3(modelMatrix*vec4(fragPosition, 1.0)); + vec3 surfaceToLight = l.position - surfacePos; + + // Diffuse shading + float brightness = clamp(float(dot(n, surfaceToLight)/(length(surfaceToLight)*length(n))), 0.0, 1.0); + float diff = 1.0/dot(surfaceToLight/l.radius, surfaceToLight/l.radius)*brightness*l.intensity; + + // Specular shading + float spec = 0.0; + if (diff > 0.0) + { + vec3 h = normalize(-l.direction + v); + spec = pow(dot(n, h), 3.0 + glossiness)*s; + } + + return (diff*l.diffuse.rgb + spec*colSpecular.rgb); +*/ + return vec3(0.5); +} + +vec3 ComputeLightDirectional(Light l, vec3 n, vec3 v, float s) +{ +/* + vec3 lightDir = normalize(-l.direction); + + // Diffuse shading + float diff = clamp(float(dot(n, lightDir)), 0.0, 1.0)*l.intensity; + + // Specular shading + float spec = 0.0; + if (diff > 0.0) + { + vec3 h = normalize(lightDir + v); + spec = pow(dot(n, h), 3.0 + glossiness)*s; + } + + // Combine results + return (diff*l.intensity*l.diffuse.rgb + spec*colSpecular.rgb); +*/ + return vec3(0.5); +} + +vec3 ComputeLightSpot(Light l, vec3 n, vec3 v, float s) +{ +/* + vec3 surfacePos = vec3(modelMatrix*vec4(fragPosition, 1)); + vec3 lightToSurface = normalize(surfacePos - l.position); + vec3 lightDir = normalize(-l.direction); + + // Diffuse shading + float diff = clamp(float(dot(n, lightDir)), 0.0, 1.0)*l.intensity; + + // Spot attenuation + float attenuation = clamp(float(dot(n, lightToSurface)), 0.0, 1.0); + attenuation = dot(lightToSurface, -lightDir); + + float lightToSurfaceAngle = degrees(acos(attenuation)); + if (lightToSurfaceAngle > l.coneAngle) attenuation = 0.0; + + float falloff = (l.coneAngle - lightToSurfaceAngle)/l.coneAngle; + + // Combine diffuse and attenuation + float diffAttenuation = diff*attenuation; + + // Specular shading + float spec = 0.0; + if (diffAttenuation > 0.0) + { + vec3 h = normalize(lightDir + v); + spec = pow(dot(n, h), 3.0 + glossiness)*s; + } + + return (falloff*(diffAttenuation*l.diffuse.rgb + spec*colSpecular.rgb)); +*/ + return vec3(0.5); +} + +void main() +{ + // Calculate fragment normal in screen space + // NOTE: important to multiply model matrix by fragment normal to apply model transformation (rotation and scale) + mat3 normalMatrix = mat3(modelMatrix); + vec3 normal = normalize(normalMatrix*fragNormal); + + // Normalize normal and view direction vectors + vec3 n = normalize(normal); + vec3 v = normalize(viewDir); + + // Calculate diffuse texture color fetching + vec4 texelColor = texture2D(texture0, fragTexCoord); + vec3 lighting = colAmbient.rgb; + + // Calculate normal texture color fetching or set to maximum normal value by default + if (useNormal == 1) + { + n *= texture2D(texture1, fragTexCoord).rgb; + n = normalize(n); + } + + // Calculate specular texture color fetching or set to maximum specular value by default + float spec = 1.0; + if (useSpecular == 1) spec *= normalize(texture2D(texture2, fragTexCoord).r); + + for (int i = 0; i < maxLights; i++) + { + // Check if light is enabled + if (lights[i].enabled == 1) + { + // Calculate lighting based on light type + if(lights[i].type == 0) lighting += ComputeLightPoint(lights[i], n, v, spec); + else if(lights[i].type == 1) lighting += ComputeLightDirectional(lights[i], n, v, spec); + else if(lights[i].type == 2) lighting += ComputeLightSpot(lights[i], n, v, spec); + + // NOTE: It seems that too many ComputeLight*() operations inside for loop breaks the shader on RPI + } + } + + // Calculate final fragment color + gl_FragColor = vec4(texelColor.rgb*lighting*colDiffuse.rgb, texelColor.a*colDiffuse.a); +} diff --git a/examples/resources/shaders/glsl100/standard.vs b/examples/resources/shaders/glsl100/standard.vs new file mode 100644 index 00000000..49c5a3eb --- /dev/null +++ b/examples/resources/shaders/glsl100/standard.vs @@ -0,0 +1,23 @@ +#version 100 + +attribute vec3 vertexPosition; +attribute vec3 vertexNormal; +attribute vec2 vertexTexCoord; +attribute vec4 vertexColor; + +varying vec3 fragPosition; +varying vec2 fragTexCoord; +varying vec4 fragColor; +varying vec3 fragNormal; + +uniform mat4 mvpMatrix; + +void main() +{ + fragPosition = vertexPosition; + fragTexCoord = vertexTexCoord; + fragColor = vertexColor; + fragNormal = vertexNormal; + + gl_Position = mvpMatrix*vec4(vertexPosition, 1.0); +} \ No newline at end of file diff --git a/examples/resources/shaders/glsl330/standard.fs b/examples/resources/shaders/glsl330/standard.fs new file mode 100644 index 00000000..14497839 --- /dev/null +++ b/examples/resources/shaders/glsl330/standard.fs @@ -0,0 +1,150 @@ +#version 330 + +in vec3 fragPosition; +in vec2 fragTexCoord; +in vec4 fragColor; +in vec3 fragNormal; + +out vec4 finalColor; + +uniform sampler2D texture0; +uniform sampler2D texture1; +uniform sampler2D texture2; + +uniform vec4 colAmbient; +uniform vec4 colDiffuse; +uniform vec4 colSpecular; +uniform float glossiness; + +uniform int useNormal; +uniform int useSpecular; + +uniform mat4 modelMatrix; +uniform vec3 viewDir; + +struct Light { + int enabled; + int type; + vec3 position; + vec3 direction; + vec4 diffuse; + float intensity; + float radius; + float coneAngle; +}; + +const int maxLights = 8; +uniform Light lights[maxLights]; + +vec3 ComputeLightPoint(Light l, vec3 n, vec3 v, float s) +{ + vec3 surfacePos = vec3(modelMatrix*vec4(fragPosition, 1)); + vec3 surfaceToLight = l.position - surfacePos; + + // Diffuse shading + float brightness = clamp(float(dot(n, surfaceToLight)/(length(surfaceToLight)*length(n))), 0.0, 1.0); + float diff = 1.0/dot(surfaceToLight/l.radius, surfaceToLight/l.radius)*brightness*l.intensity; + + // Specular shading + float spec = 0.0; + if (diff > 0.0) + { + vec3 h = normalize(-l.direction + v); + spec = pow(dot(n, h), 3.0 + glossiness)*s; + } + + return (diff*l.diffuse.rgb + spec*colSpecular.rgb); +} + +vec3 ComputeLightDirectional(Light l, vec3 n, vec3 v, float s) +{ + vec3 lightDir = normalize(-l.direction); + + // Diffuse shading + float diff = clamp(float(dot(n, lightDir)), 0.0, 1.0)*l.intensity; + + // Specular shading + float spec = 0.0; + if (diff > 0.0) + { + vec3 h = normalize(lightDir + v); + spec = pow(dot(n, h), 3.0 + glossiness)*s; + } + + // Combine results + return (diff*l.intensity*l.diffuse.rgb + spec*colSpecular.rgb); +} + +vec3 ComputeLightSpot(Light l, vec3 n, vec3 v, float s) +{ + vec3 surfacePos = vec3(modelMatrix*vec4(fragPosition, 1)); + vec3 lightToSurface = normalize(surfacePos - l.position); + vec3 lightDir = normalize(-l.direction); + + // Diffuse shading + float diff = clamp(float(dot(n, lightDir)), 0.0, 1.0)*l.intensity; + + // Spot attenuation + float attenuation = clamp(float(dot(n, lightToSurface)), 0.0, 1.0); + attenuation = dot(lightToSurface, -lightDir); + + float lightToSurfaceAngle = degrees(acos(attenuation)); + if (lightToSurfaceAngle > l.coneAngle) attenuation = 0.0; + + float falloff = (l.coneAngle - lightToSurfaceAngle)/l.coneAngle; + + // Combine diffuse and attenuation + float diffAttenuation = diff*attenuation; + + // Specular shading + float spec = 0.0; + if (diffAttenuation > 0.0) + { + vec3 h = normalize(lightDir + v); + spec = pow(dot(n, h), 3.0 + glossiness)*s; + } + + return (falloff*(diffAttenuation*l.diffuse.rgb + spec*colSpecular.rgb)); +} + +void main() +{ + // Calculate fragment normal in screen space + // NOTE: important to multiply model matrix by fragment normal to apply model transformation (rotation and scale) + mat3 normalMatrix = mat3(modelMatrix); + vec3 normal = normalize(normalMatrix*fragNormal); + + // Normalize normal and view direction vectors + vec3 n = normalize(normal); + vec3 v = normalize(viewDir); + + // Calculate diffuse texture color fetching + vec4 texelColor = texture(texture0, fragTexCoord); + vec3 lighting = colAmbient.rgb; + + // Calculate normal texture color fetching or set to maximum normal value by default + if (useNormal == 1) + { + n *= texture(texture1, fragTexCoord).rgb; + n = normalize(n); + } + + // Calculate specular texture color fetching or set to maximum specular value by default + float spec = 1.0; + if (useSpecular == 1) spec *= normalize(texture(texture2, fragTexCoord).r); + + for (int i = 0; i < maxLights; i++) + { + // Check if light is enabled + if (lights[i].enabled == 1) + { + // Calculate lighting based on light type + if (lights[i].type == 0) lighting += ComputeLightPoint(lights[i], n, v, spec); + else if (lights[i].type == 1) lighting += ComputeLightDirectional(lights[i], n, v, spec); + else if (lights[i].type == 2) lighting += ComputeLightSpot(lights[i], n, v, spec); + } + } + + // Calculate final fragment color + finalColor = vec4(texelColor.rgb*lighting*colDiffuse.rgb, texelColor.a*colDiffuse.a); +} diff --git a/examples/resources/shaders/glsl330/standard.vs b/examples/resources/shaders/glsl330/standard.vs new file mode 100644 index 00000000..fc0a5ff4 --- /dev/null +++ b/examples/resources/shaders/glsl330/standard.vs @@ -0,0 +1,23 @@ +#version 330 + +in vec3 vertexPosition; +in vec3 vertexNormal; +in vec2 vertexTexCoord; +in vec4 vertexColor; + +out vec3 fragPosition; +out vec2 fragTexCoord; +out vec4 fragColor; +out vec3 fragNormal; + +uniform mat4 mvpMatrix; + +void main() +{ + fragPosition = vertexPosition; + fragTexCoord = vertexTexCoord; + fragColor = vertexColor; + fragNormal = vertexNormal; + + gl_Position = mvpMatrix*vec4(vertexPosition, 1.0); +} \ No newline at end of file -- cgit v1.2.3